D'abord un avertissement préalable: les extraits de code publiés sont tous des exemples de base. Vous devrez gérer les éléments triviaux IOException
et RuntimeException
similaires NullPointerException
, ArrayIndexOutOfBoundsException
et vous épouser.
En train de préparer
Nous devons d'abord connaître au moins l'URL et le jeu de caractères. Les paramètres sont facultatifs et dépendent des exigences fonctionnelles.
String url = "http://example.com";
String charset = "UTF-8"; // Or in Java 7 and later, use the constant: java.nio.charset.StandardCharsets.UTF_8.name()
String param1 = "value1";
String param2 = "value2";
// ...
String query = String.format("param1=%s¶m2=%s",
URLEncoder.encode(param1, charset),
URLEncoder.encode(param2, charset));
Les paramètres de requête doivent être au name=value
format et être concaténés par &
. Normalement, vous devez également encoder par URL les paramètres de requête avec le jeu de caractères spécifié à l'aide de URLEncoder#encode()
.
C'est String#format()
juste pour plus de commodité. Je le préfère lorsque j'aurais besoin de l'opérateur de concaténation de chaînes +
plus de deux fois.
Lancer une requête HTTP GET avec (facultativement) des paramètres de requête
C'est une tâche insignifiante. C'est la méthode de demande par défaut.
URLConnection connection = new URL(url + "?" + query).openConnection();
connection.setRequestProperty("Accept-Charset", charset);
InputStream response = connection.getInputStream();
// ...
Toute chaîne de requête doit être concaténée avec l'URL à l'aide de ?
. L'en- Accept-Charset
tête peut indiquer au serveur le codage des paramètres. Si vous n'envoyez aucune chaîne de requête, vous pouvez laisser l'en- Accept-Charset
tête à l'écart. Si vous n'avez pas besoin de définir d'en-têtes, vous pouvez même utiliser la URL#openStream()
méthode de raccourci.
InputStream response = new URL(url).openStream();
// ...
Dans les deux cas, si l'autre côté est un HttpServlet
, sa doGet()
méthode sera appelée et les paramètres seront disponibles par HttpServletRequest#getParameter()
.
À des fins de test, vous pouvez imprimer le corps de la réponse sur stdout comme ci-dessous:
try (Scanner scanner = new Scanner(response)) {
String responseBody = scanner.useDelimiter("\\A").next();
System.out.println(responseBody);
}
Lancer une requête HTTP POST avec des paramètres de requête
Réglage de la URLConnection#setDoOutput()
à true
définit implicitement la méthode de requête POST à. Le HTTP POST standard comme le font les formulaires Web est de type application/x-www-form-urlencoded
dans lequel la chaîne de requête est écrite dans le corps de la demande.
URLConnection connection = new URL(url).openConnection();
connection.setDoOutput(true); // Triggers POST.
connection.setRequestProperty("Accept-Charset", charset);
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=" + charset);
try (OutputStream output = connection.getOutputStream()) {
output.write(query.getBytes(charset));
}
InputStream response = connection.getInputStream();
// ...
Remarque: chaque fois que vous souhaitez soumettre un formulaire HTML par programme, n'oubliez pas de prendre les name=value
paires d' <input type="hidden">
éléments dans la chaîne de requête et bien sûr aussi la name=value
paire de l' <input type="submit">
élément sur lequel vous souhaitez "appuyer" par programme (car qui a généralement été utilisé côté serveur pour distinguer si un bouton a été enfoncé et si oui, lequel).
Vous pouvez également jeter l'obtenu URLConnection
à HttpURLConnection
et utiliser sa HttpURLConnection#setRequestMethod()
place. Mais si vous essayez d'utiliser la connexion pour la sortie, vous devez toujours la régler URLConnection#setDoOutput()
sur true
.
HttpURLConnection httpConnection = (HttpURLConnection) new URL(url).openConnection();
httpConnection.setRequestMethod("POST");
// ...
Dans les deux cas, si l'autre côté est un HttpServlet
, sa doPost()
méthode sera appelée et les paramètres seront disponibles par HttpServletRequest#getParameter()
.
Déclencher réellement la requête HTTP
Vous pouvez déclencher explicitement la demande HTTP avec URLConnection#connect()
, mais la demande sera automatiquement déclenchée à la demande lorsque vous souhaitez obtenir des informations sur la réponse HTTP, telles que le corps de la réponse à l'aide de URLConnection#getInputStream()
etc. Les exemples ci-dessus font exactement cela, donc l' connect()
appel est en fait superflu.
Collecte des informations de réponse HTTP
Statut de réponse HTTP :
Vous en avez besoin HttpURLConnection
ici. Jetez-le d'abord si nécessaire.
int status = httpConnection.getResponseCode();
En-têtes de réponse HTTP :
for (Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) {
System.out.println(header.getKey() + "=" + header.getValue());
}
Encodage de réponse HTTP :
Lorsque le Content-Type
contient un charset
paramètre, le corps de la réponse est probablement basé sur du texte et nous aimerions alors traiter le corps de la réponse avec le codage de caractères spécifié côté serveur.
String contentType = connection.getHeaderField("Content-Type");
String charset = null;
for (String param : contentType.replace(" ", "").split(";")) {
if (param.startsWith("charset=")) {
charset = param.split("=", 2)[1];
break;
}
}
if (charset != null) {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(response, charset))) {
for (String line; (line = reader.readLine()) != null;) {
// ... System.out.println(line) ?
}
}
} else {
// It's likely binary content, use InputStream/OutputStream.
}
Maintenir la session
La session côté serveur est généralement soutenue par un cookie. Certains formulaires Web nécessitent que vous soyez connecté et / ou que vous soyez suivi par une session. Vous pouvez utiliser l' CookieHandler
API pour gérer les cookies. Vous devez préparer un CookieManager
avec CookiePolicy
des ACCEPT_ALL
avant d' envoyer toutes les requêtes HTTP.
// First set the default cookie manager.
CookieHandler.setDefault(new CookieManager(null, CookiePolicy.ACCEPT_ALL));
// All the following subsequent URLConnections will use the same cookie manager.
URLConnection connection = new URL(url).openConnection();
// ...
connection = new URL(url).openConnection();
// ...
connection = new URL(url).openConnection();
// ...
Notez que cela est connu pour ne pas toujours fonctionner correctement en toutes circonstances. Si cela échoue pour vous, le mieux est de rassembler et de définir manuellement les en-têtes des cookies. Vous devez essentiellement récupérer tous les en- Set-Cookie
têtes de la réponse de la connexion ou de la première GET
demande, puis les transmettre aux demandes suivantes.
// Gather all cookies on the first request.
URLConnection connection = new URL(url).openConnection();
List<String> cookies = connection.getHeaderFields().get("Set-Cookie");
// ...
// Then use the same cookies on all subsequent requests.
connection = new URL(url).openConnection();
for (String cookie : cookies) {
connection.addRequestProperty("Cookie", cookie.split(";", 2)[0]);
}
// ...
Le split(";", 2)[0]
est là pour se débarrasser des attributs de cookie qui ne sont pas pertinents pour le côté serveur comme expires
, path
, etc. Sinon, vous pouvez également utiliser au cookie.substring(0, cookie.indexOf(';'))
lieu de split()
.
Mode streaming
Le HttpURLConnection
testament par défaut met en mémoire tampon tout le corps de la requête avant de l'envoyer, que vous ayez défini vous-même une longueur de contenu fixe connection.setRequestProperty("Content-Length", contentLength);
. Cela peut entraîner des OutOfMemoryException
s lorsque vous envoyez simultanément des demandes POST volumineuses (par exemple, le téléchargement de fichiers). Pour éviter cela, vous souhaitez définir le HttpURLConnection#setFixedLengthStreamingMode()
.
httpConnection.setFixedLengthStreamingMode(contentLength);
Mais si la longueur du contenu n'est vraiment pas connue à l'avance, vous pouvez utiliser le mode de diffusion en morceaux en définissant le en HttpURLConnection#setChunkedStreamingMode()
conséquence. Cela définira l'en- Transfer-Encoding
tête HTTP sur chunked
lequel forcera l'envoi du corps de la demande par blocs. L'exemple ci-dessous enverra le corps en morceaux de 1 Ko.
httpConnection.setChunkedStreamingMode(1024);
Agent utilisateur
Il peut arriver qu'une demande renvoie une réponse inattendue, alors qu'elle fonctionne correctement avec un véritable navigateur Web . Le côté serveur bloque probablement les demandes sur la base de l'en- User-Agent
tête de demande. La URLConnection
volonté par défaut le placera là Java/1.6.0_19
où la dernière partie est évidemment la version JRE. Vous pouvez remplacer cela comme suit:
connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36"); // Do as if you're using Chrome 41 on Windows 7.
Utilisez la chaîne User-Agent d'un navigateur récent .
La gestion des erreurs
Si le code de réponse HTTP est 4nn
(Erreur client) ou 5nn
(Erreur serveur), vous pouvez lire le HttpURLConnection#getErrorStream()
pour voir si le serveur a envoyé des informations d'erreur utiles.
InputStream error = ((HttpURLConnection) connection).getErrorStream();
Si le code de réponse HTTP est -1, quelque chose s'est mal passé avec la connexion et la gestion des réponses. L' HttpURLConnection
implémentation est dans les anciens JRE quelque peu boguée avec le maintien des connexions en vie. Vous pouvez le désactiver en définissant la http.keepAlive
propriété système sur false
. Vous pouvez le faire par programme au début de votre application en:
System.setProperty("http.keepAlive", "false");
Téléchargement de fichiers
Vous utiliseriez normalement l' multipart/form-data
encodage pour le contenu POST mixte (données binaires et caractères). Le codage est décrit plus en détail dans la RFC2388 .
String param = "value";
File textFile = new File("/path/to/file.txt");
File binaryFile = new File("/path/to/file.bin");
String boundary = Long.toHexString(System.currentTimeMillis()); // Just generate some unique random value.
String CRLF = "\r\n"; // Line separator required by multipart/form-data.
URLConnection connection = new URL(url).openConnection();
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
try (
OutputStream output = connection.getOutputStream();
PrintWriter writer = new PrintWriter(new OutputStreamWriter(output, charset), true);
) {
// Send normal param.
writer.append("--" + boundary).append(CRLF);
writer.append("Content-Disposition: form-data; name=\"param\"").append(CRLF);
writer.append("Content-Type: text/plain; charset=" + charset).append(CRLF);
writer.append(CRLF).append(param).append(CRLF).flush();
// Send text file.
writer.append("--" + boundary).append(CRLF);
writer.append("Content-Disposition: form-data; name=\"textFile\"; filename=\"" + textFile.getName() + "\"").append(CRLF);
writer.append("Content-Type: text/plain; charset=" + charset).append(CRLF); // Text file itself must be saved in this charset!
writer.append(CRLF).flush();
Files.copy(textFile.toPath(), output);
output.flush(); // Important before continuing with writer!
writer.append(CRLF).flush(); // CRLF is important! It indicates end of boundary.
// Send binary file.
writer.append("--" + boundary).append(CRLF);
writer.append("Content-Disposition: form-data; name=\"binaryFile\"; filename=\"" + binaryFile.getName() + "\"").append(CRLF);
writer.append("Content-Type: " + URLConnection.guessContentTypeFromName(binaryFile.getName())).append(CRLF);
writer.append("Content-Transfer-Encoding: binary").append(CRLF);
writer.append(CRLF).flush();
Files.copy(binaryFile.toPath(), output);
output.flush(); // Important before continuing with writer!
writer.append(CRLF).flush(); // CRLF is important! It indicates end of boundary.
// End of multipart/form-data.
writer.append("--" + boundary + "--").append(CRLF).flush();
}
Si l'autre côté est un HttpServlet
, alors sa doPost()
méthode sera appelée et les pièces seront disponibles par HttpServletRequest#getPart()
(notez donc pas getParameter()
et ainsi de suite!). La getPart()
méthode est cependant relativement nouvelle, elle est introduite dans Servlet 3.0 (Glassfish 3, Tomcat 7, etc.). Avant Servlet 3.0, votre meilleur choix est d'utiliser Apache Commons FileUpload pour analyser une multipart/form-data
demande. Consultez également cette réponse pour des exemples des approches FileUpload et Servelt 3.0.
Gestion des sites HTTPS non fiables ou mal configurés
Parfois, vous devez connecter une URL HTTPS, peut-être parce que vous écrivez un grattoir Web. Dans ce cas, vous pouvez probablement rencontrer un javax.net.ssl.SSLException: Not trusted server certificate
sur certains sites HTTPS qui ne tiennent pas à jour leurs certificats SSL, ou un java.security.cert.CertificateException: No subject alternative DNS name matching [hostname] found
ou javax.net.ssl.SSLProtocolException: handshake alert: unrecognized_name
sur certains sites HTTPS mal configurés.
L' static
initialiseur à exécution unique suivant dans votre classe Web Scraper devrait rendre HttpsURLConnection
plus indulgents ces sites HTTPS et donc ne plus lever ces exceptions.
static {
TrustManager[] trustAllCertificates = new TrustManager[] {
new X509TrustManager() {
@Override
public X509Certificate[] getAcceptedIssuers() {
return null; // Not relevant.
}
@Override
public void checkClientTrusted(X509Certificate[] certs, String authType) {
// Do nothing. Just allow them all.
}
@Override
public void checkServerTrusted(X509Certificate[] certs, String authType) {
// Do nothing. Just allow them all.
}
}
};
HostnameVerifier trustAllHostnames = new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true; // Just allow them all.
}
};
try {
System.setProperty("jsse.enableSNIExtension", "false");
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCertificates, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(trustAllHostnames);
}
catch (GeneralSecurityException e) {
throw new ExceptionInInitializerError(e);
}
}
Derniers mots
L' Apache HttpComponents HttpClient est beaucoup plus pratique dans tout cela :)
Analyse et extraction de HTML
Si tout ce que vous voulez c'est analyser et extraire des données de HTML, alors mieux vaut utiliser un analyseur HTML comme Jsoup
Ask Question
bouton en haut à droite.--
partie ne fait pas partie de la frontière elle-même. C'est juste une chaîne de séparation. J'ai annulé votre modification non valide.HttpClient
maintenant etHttpURLConnection
est cruel. android-developers.blogspot.in/2011/09/…Lorsque vous travaillez avec HTTP, il est presque toujours plus utile de se référer à
HttpURLConnection
la classe de baseURLConnection
(car ilURLConnection
s'agit d'une classe abstraite lorsque vous demandezURLConnection.openConnection()
une URL HTTP, c'est ce que vous obtiendrez de toute façon).Ensuite, vous pouvez au lieu de vous fier
URLConnection#setDoOutput(true)
à définir implicitement la méthode de demande sur POST à la place, cehttpURLConnection.setRequestMethod("POST")
que certains pourraient trouver plus naturel (et qui vous permet également de spécifier d'autres méthodes de demande telles que PUT , DELETE , ...).Il fournit également des constantes HTTP utiles pour que vous puissiez faire:
la source
setDoOutput()
surtrue
sinon une exception est levée (même si voussetRequestMethod("POST")
). Pour être clair: la définitionURLConnection#setDoOutput(true)
detrue
définit implicitement la méthode de demande sur POST, mais la définitionhttpURLConnection.setRequestMethod("POST")
de POST n'est pas implicitement définiesetDoOutput()
surtrue
.Inspiré par cela et d'autres questions sur SO, j'ai créé un client http-basic- open source minimal qui incarne la plupart des techniques trouvées ici.
google-http-java-client est également une excellente ressource open source.
la source
Je vous suggère de jeter un oeil au code sur kevinsawicki / http-request , c'est essentiellement un wrapper au-dessus
HttpUrlConnection
qui fournit une API beaucoup plus simple au cas où vous voudriez simplement faire les demandes maintenant ou vous pouvez jeter un oeil aux sources ( ce n'est pas trop gros) pour voir comment les connexions sont gérées.Exemple: effectuez une
GET
demande avec le type de contenuapplication/json
et certains paramètres de requête:la source
Il y a 2 options que vous pouvez utiliser avec les URL URL HTTP: GET / POST
OBTENIR la demande: -
Demande POST: -
la source
J'ai également été très inspiré par cette réponse.
Je suis souvent sur des projets où j'ai besoin de faire du HTTP, et je ne veux peut-être pas apporter beaucoup de dépendances tierces (qui en amènent d'autres et ainsi de suite et ainsi de suite, etc.)
J'ai commencé à écrire mes propres utilitaires sur la base d'une partie de cette conversation (pas n'importe où):
Ensuite, il y a juste un tas ou des méthodes statiques.
Ensuite, postez ...
Eh bien, vous avez l'idée ....
Voici les tests:
Vous pouvez trouver le reste ici:
https://github.com/RichardHightower/boon
Mon objectif est de fournir les choses courantes que l'on voudrait faire de manière un peu plus facile que ...
la source
doPost
méthode il y ait uncharset
paramètre, qui est utilisé pour définir l'en-tête de la demande, mais ensuite les données sont écrites avec un jeu de caractères codé en durIO.CHARSET
. Un bug?Mise à jour
Dans Java 9, vous pouvez envoyer une
GET
demande comme:Ensuite, vous pouvez examiner le retour
HttpResponse
:Puisque ce nouveau client HTTP est en
java.httpclient
jdk.incubator.httpclient
module, vous devez déclarer cette dépendance dans votremodule-info.java
fichier:la source
Au début, j'ai été induit en erreur par cette article qui favorise
HttpClient
.Plus tard, j'ai réalisé que
HttpURLConnection
allait rester de cet articleSelon le blog Google :
Après avoir lu cet article et quelques autres questions sur la pile de flux, je suis convaincu que
HttpURLConnection
va durer plus longtemps.Certaines des questions SE favorisant
HttpURLConnections
:Sur Android, effectuez une demande POST avec des données de formulaire encodées URL sans utiliser UrlEncodedFormEntity
HttpPost fonctionne dans le projet Java, pas dans Android
la source
Il existe également OkHttp , qui est un client HTTP efficace par défaut:
Créez d'abord une instance de
OkHttpClient
:Ensuite, préparez votre
GET
demande:enfin, utilisez
OkHttpClient
pour envoyer préparéRequest
:Pour plus de détails, vous pouvez consulter la documentation d'OkHttp
la source
Vous pouvez également utiliser à
JdkRequest
partir de jcabi-http (je suis développeur), qui fait tout ce travail pour vous, décorer HttpURLConnection, lancer des requêtes HTTP et analyser les réponses, par exemple:Consultez cet article de blog pour plus d'informations: http://www.yegor256.com/2014/04/11/jcabi-http-intro.html
la source
si vous utilisez http get, veuillez supprimer cette ligne
la source