[JAVA] [Aktualisierung] Es war schwierig, ein Upgrade von der httpclient 3.x-Serie auf 4.5 durchzuführen, daher werde ich eine Zusammenfassung der Änderungen schreiben

Ich weiß nicht, was ich getan habe, also schreibe ich auf, was ich geändert habe.

Ich durfte mich beziehen.

** Unterstützt wichtige Änderungen an der Benutzeroberfläche von Java Apache HttpClient 4.3 (@mychaelstyle) ** https://qiita.com/mychaelstyle/items/e02b3011d1e71bfa26c5 ** Apache httpclient CloseableHttpClient an HTTPS-Site-Anfrage mit BASIC-Authentifizierung (@sh_kawakami) ** https://qiita.com/sh_kawakami/items/bf6d1397851cccd134b2 ** Es scheint, dass sich die Oberfläche von httpclient von 4.3 (@sakito) erheblich geändert hat ** https://qiita.com/sakito/items/6366015dbbc4a88d56fc What does setDefaultMaxPerRoute and setMaxTotal mean in HttpClient? Antwortspalte von https://stackoverflow.com/questions/30689995/what-does-setdefaultmaxperroute-and-setmaxtotal-mean-in-httpclient

Umgebung

JDK 1.8.162 httpclient 4.5.4

pom.xml

pom.xml


<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.4</version>
</dependency>

Schöne veraltete Liste

Ich habe mich umgesehen, als hätte mir die veraltete Liste noch nie geholfen

―― 3.x-Serie https://hc.apache.org/httpclient-3.x/apidocs/deprecated-list.html ―― 4.x Serie http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/deprecated-list.html

Schönes Tutorial

http://hc.apache.org/httpcomponents-client-ga/tutorial/html/index.html

Schöne Kurzanleitung

Da es sich um eine Richtlinie beim Erhöhen von 3.x auf 4.0 handelt, kann es sich bei Erreichen von 4.5 erneut ändern. http://debuguide.blogspot.jp/2013/01/quick-guide-for-migration-of-commons.html

Liste nützlicher Konstanten

―― 3.x-Serie https://hc.apache.org/httpclient-3.x/apidocs/constant-values.html ―― 4.x Serie http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/constant-values.html

Beseitigen Sie Kompilierungsfehler

Paketänderung

Wechseln Sie zur Standard-API

Ein System, das völlig anders ist

Die Art und Weise, eine Instanz zu erstellen, hat sich in erster Linie geändert

before.java


HttpClient client = new HttpClient();

Verwenden wir Builder! Es scheint, dass. Wenn Sie an nichts denken müssen, siehe unten.

after.java


HttpClient client = HttpClients.createDefault();

Dies ist jedoch möglicherweise nicht sehr praktisch, da Sie die Verbindungseinstellungen zum Zeitpunkt der Generierung übergeben müssen.

Änderung der Methodenklasse

GetMethod→HttpGet PostMethod→HttpPost Übergeordnete Klasse HttpMethod → HttpRequestBase Ändern

Ausführung & Antwort erhalten

Früher war es so

before.java


PostMethod post = new PostMethod(url);
post.setRequestEntity(Setze etwas);
int responseCode = client.executeMethod(post);
if (responseCode == 200) {
	Reader reader = new InputStreamReader(
			httpMethod.getResponseBodyAsStream(), httpMethod.getResponseCharSet());
	//Nachbearbeitung
} else {
  //Fehlerbehandlung
}

Es hat sich sehr verändert und sieht so aus. Aber jetzt, da es klar ist, ist es vielleicht einfacher zu verstehen.

after.java


HttpPost post = new HttpPost(url);
//Legen Sie diejenige fest, die dem Anforderungshauptteil entspricht
post.setEntity(Setze etwas);
HttpResponse response = client.execute(post);
StatusLine statusLine = response.getStatusLine();
int responseCode = statusLine.getStatusCode();
if (responseCode == HttpStatus.SC_OK) {
	Reader reader = new InputStreamReader(
			response.getEntity().getContent(), Charset.forName("UTF-8"));
	//Nachbearbeitung
} else {
	//Fehlerbehandlung
}

Rund um die grundlegende Authentifizierungsverbindung

Ich habe es so gemacht.

before.java


Credentials credentials = new UsernamePasswordCredentials(this.username, this.password);
AuthScope scope = new AuthScope(host, port, this.realm);
client.getState().setCredentials(scope, credentials);

Es scheint, dass Sie CredentialsProvider verwenden sollten. (Danke an @sh_kawakami!)

after.java


CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(new AuthScope(baseUrl.getHost(),baseUrl.getPort()),
        new UsernamePasswordCredentials(username, password));
//Ich werde es beim Erstellen einer Instanz festlegen
HttpClient client = HttpClients.custom().setDefaultCredentialsProvider(credentialsProvider).build();

NameValuePair-Schnittstelle

Es scheint, dass die Entitätsklasse jetzt BasicNameValuePair ist. Es scheint, dass es nur durch "=" geteilt wird, also bete ich, dass sich das Verhalten nicht wie zuvor ändert. Aber der Setter ist weg! !! !! Aus meiner Sicht kann es anscheinend nur mit dem Konstruktor festgelegt werden. Wenn Sie Setter weiterhin verwenden möchten, müssen Sie NameValuePair erben und eine eigene Klasse erstellen.

Dies und das verursachte zur Laufzeit einen Fehler

Der Standard-HttpClient sendet den Host-Header nicht mehr

Lassen Sie es uns selbst hinzufügen

//Host-Header
httpMethod.addHeader("Host", uri.getHost());

ConnectionClosedException tritt auf, wenn Content-Length-Header und ResponseBody-Größe nicht übereinstimmen

Tritt auf, wenn sich die Größe der Antwort vom Text unterscheidet, wenn ein Content-Length-Header vorhanden ist. Dies geschieht nicht ohne den Content-Length-Header (obwohl es sich wie eine RFC-Verletzung anfühlt). Zum Beispiel tritt es auf, wenn die Antwort so ist. Nun, heute denke ich, dass die Inhaltslänge automatisch vom Server ohne Erlaubnis berechnet und zurückgegeben wird, daher denke ich, dass dies unwahrscheinlich ist, aber aus verschiedenen Gründen vertraue ich dem Antwortheader nicht.

HTTP/1.1 200 OK
Content-Type: text/html; charset=Shift_JIS
Content-Length: 3000
<html>
<head><title>Hoge</title>
</head>
<body>test
</body>
</html>
org.apache.http.ConnectionClosedException: Premature end of Content-Length delimited message body (expected: 3000; received: 124
	at org.apache.http.impl.io.ContentLengthInputStream.read(ContentLengthInputStream.java:178)
	at org.apache.http.conn.EofSensorInputStream.read(EofSensorInputStream.java:135)
	at org.apache.http.conn.EofSensorInputStream.read(EofSensorInputStream.java:148)

Die Ursache ist hier

java:org.apache.http.impl.io.ContentLengthInputStream.java


    /**
     * Does standard {@link InputStream#read(byte[], int, int)} behavior, but
     * also notifies the watcher when the contents have been consumed.
     *
     * @param b     The byte array to fill.
     * @param off   Start filling at this position.
     * @param len   The number of bytes to attempt to read.
     * @return The number of bytes read, or -1 if the end of content has been
     *  reached.
     *
     * @throws java.io.IOException Should an error occur on the wrapped stream.
     */
    @Override
    public int read (final byte[] b, final int off, final int len) throws java.io.IOException {
        if (closed) {
            throw new IOException("Attempted read from closed stream.");
        }

        if (pos >= contentLength) {
            return -1;
        }

        int chunk = len;
        if (pos + len > contentLength) {
            chunk = (int) (contentLength - pos);
        }
        final int count = this.in.read(b, off, chunk);
        if (count == -1 && pos < contentLength) {
            throw new ConnectionClosedException(
                    "Premature end of Content-Length delimited message body (expected: "
                    + contentLength + "; received: " + pos);
        }
        if (count > 0) {
            pos += count;
        }
        return count;
    }

Ich habe bisher keine Lösung gefunden.

Fehler, dass Zertifikat und Hostname während der SSL-Kommunikation nicht übereinstimmen (einschließlich Selbstzertifikat)

javax.net.ssl.SSLPeerUnverifiedException: Certificate for <hostname> doesn't match any of the subject alternative names:

Es scheint, dass der Hostname standardmäßig überprüft wird. Der relevante Teil ist hier

java:org.apache.http.conn.ssl.SSLConnectionSocketFactory.java#verifyHostname


            if (!this.hostnameVerifier.verify(hostname, session)) {
                final Certificate[] certs = session.getPeerCertificates();
                final X509Certificate x509 = (X509Certificate) certs[0];
                final List<SubjectName> subjectAlts = DefaultHostnameVerifier.getSubjectAltNames(x509);
                throw new SSLPeerUnverifiedException("Certificate for <" + hostname + "> doesn't match any " +
                        "of the subject alternative names: " + subjectAlts);
            }

Es scheint, dass Sie eine Instanz der NoopHostnameVerifier-Klasse verwenden können, da verify nur true zurückgeben muss. Deaktivieren Sie die Überprüfung des SSL-Zertifikats und des Hostnamens in Apache HttpComponents / Client Chapter 2. Connection management 2.7.4. Hostname verification In meinem Fall setze ich SSLContext oder SSLConnectionSocketFactory nicht direkt in httpclient, sondern implementiere es, indem ich es in ConnectionManager einstelle. An diesem Punkt. Es sieht also wie folgt aus.

public static PoolingHttpClientConnectionManager createConnectionManager() {
    SSLContext sslContext = null;
	try {
		sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy(){
			@Override
			public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
				return true;
			}
		}
		).build();
	} catch (Exception e) {
		e.printStackTrace();
	}
	SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
	Registry<ConnectionSocketFactory> registry =
			RegistryBuilder.<ConnectionSocketFactory>create()
					.register("http", PlainConnectionSocketFactory.getSocketFactory())
					.register("https", sslsf)
					.build();
	return new PoolingHttpClientConnectionManager(registry);
}

Andere Websites, auf die ich verwiesen habe

Der DefaultHttpRequestRetryHandler von Apache HttpClient versucht es nicht erneut mit ConnectTimeoutException http://kntmr.hatenablog.com/entry/2016/12/09/150615 Use of non-ascii credentials not working in httpclient 4.3.x https://stackoverflow.com/questions/27955067/use-of-non-ascii-credentials-not-working-in-httpclient-4-3-x

Recommended Posts

[Aktualisierung] Es war schwierig, ein Upgrade von der httpclient 3.x-Serie auf 4.5 durchzuführen, daher werde ich eine Zusammenfassung der Änderungen schreiben
Rails war schwierig, deshalb habe ich so etwas wie einen Spring Framework-Controller gemacht, um eine Pause einzulegen
Ich konnte OCJP Silver SE 11 sicher erhalten, also eine Zusammenfassung
Zusammenfassung der Punkte, über die ich mir bei der Migration von Java nach Kotlin Sorgen gemacht habe
Zusammenfassung des Mooses beim Update von JMockit 1.4 auf 1.30
Kintone-Klon? Ich war ziemlich süchtig danach, die OSS WebDB-Erweiterung mit Lightsail + Docker zu starten. Notieren Sie sich dies.