Primero un descargo de responsabilidad de antemano: los fragmentos de código publicados son todos ejemplos básicos. Tendrás que manejar cosas triviales IOException
y me RuntimeException
gusta NullPointerException
, ArrayIndexOutOfBoundsException
y consorte tú mismo.
Preparando
Primero necesitamos saber al menos la URL y el juego de caracteres. Los parámetros son opcionales y dependen de los requisitos funcionales.
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));
Los parámetros de consulta deben estar en name=value
formato y estar concatenados por &
. Normalmente también codificaría en URL los parámetros de consulta con el juego de caracteres especificado utilizando URLEncoder#encode()
.
El String#format()
es solo por conveniencia. Lo prefiero cuando necesito el operador de concatenación de cadenas +
más de dos veces.
Disparando una solicitud HTTP GET con (opcionalmente) parámetros de consulta
Es una tarea trivial. Es el método de solicitud predeterminado.
URLConnection connection = new URL(url + "?" + query).openConnection();
connection.setRequestProperty("Accept-Charset", charset);
InputStream response = connection.getInputStream();
// ...
Cualquier cadena de consulta se debe concatenar a la URL usando ?
. El Accept-Charset
encabezado puede indicar al servidor en qué codificación se encuentran los parámetros. Si no envía ninguna cadena de consulta, puede dejar el Accept-Charset
encabezado ausente. Si no necesita configurar ningún encabezado, incluso puede usar el URL#openStream()
método de acceso directo.
InputStream response = new URL(url).openStream();
// ...
De cualquier manera, si el otro lado es a HttpServlet
, entonces doGet()
se llamará a su método y los parámetros estarán disponibles por HttpServletRequest#getParameter()
.
Para fines de prueba, puede imprimir el cuerpo de respuesta en stdout de la siguiente manera:
try (Scanner scanner = new Scanner(response)) {
String responseBody = scanner.useDelimiter("\\A").next();
System.out.println(responseBody);
}
Disparando una solicitud HTTP POST con parámetros de consulta
Establecer el URLConnection#setDoOutput()
para true
implícitamente establece el método de solicitud a POST. El HTTP POST estándar como lo hacen los formularios web es del tipo application/x-www-form-urlencoded
en el que la cadena de consulta se escribe en el cuerpo de la solicitud.
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();
// ...
Nota: cada vez que desee enviar un formulario HTML mediante programación, no olvide tomar los name=value
pares de cualquier <input type="hidden">
elemento en la cadena de consulta y, por supuesto, también el name=value
par del <input type="submit">
elemento que desea "presionar" mediante programación (porque eso generalmente se ha utilizado en el lado del servidor para distinguir si se presionó un botón y, de ser así, cuál).
También puede emitir el obtenido URLConnection
a HttpURLConnection
y utilizar su HttpURLConnection#setRequestMethod()
lugar. Pero si usted está tratando de utilizar la conexión para la salida todavía necesita conjunto URLConnection#setDoOutput()
a true
.
HttpURLConnection httpConnection = (HttpURLConnection) new URL(url).openConnection();
httpConnection.setRequestMethod("POST");
// ...
De cualquier manera, si el otro lado es a HttpServlet
, entonces doPost()
se llamará a su método y los parámetros estarán disponibles por HttpServletRequest#getParameter()
.
En realidad disparando la solicitud HTTP
Puede disparar la solicitud HTTP explícitamente URLConnection#connect()
, pero la solicitud se disparará automáticamente a pedido cuando desee obtener información sobre la respuesta HTTP, como el cuerpo de la respuesta que usa, URLConnection#getInputStream()
etc. Los ejemplos anteriores hacen exactamente eso, por lo que la connect()
llamada es de hecho superflua.
Recopilación de información de respuesta HTTP
Estado de respuesta HTTP :
Necesitas un HttpURLConnection
aquí. Echa primero si es necesario.
int status = httpConnection.getResponseCode();
Encabezados de respuesta HTTP :
for (Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) {
System.out.println(header.getKey() + "=" + header.getValue());
}
Codificación de respuesta HTTP :
Cuando Content-Type
contiene un charset
parámetro, es probable que el cuerpo de la respuesta esté basado en texto y nos gustaría procesar el cuerpo de la respuesta con la codificación de caracteres especificada en el lado del servidor.
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.
}
Manteniendo la sesión
La sesión del lado del servidor generalmente está respaldada por una cookie. Algunos formularios web requieren que haya iniciado sesión y / o que una sesión los rastree. Puede usar la CookieHandler
API para mantener las cookies. Es necesario preparar una CookieManager
con una CookiePolicy
de ACCEPT_ALL
antes de enviar todas las peticiones 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();
// ...
Tenga en cuenta que se sabe que esto no siempre funciona correctamente en todas las circunstancias. Si falla para usted, lo mejor es reunir y configurar manualmente los encabezados de las cookies. Básicamente, debe tomar todos los Set-Cookie
encabezados de la respuesta del inicio de sesión o la primera GET
solicitud y luego pasar esto a través de las solicitudes posteriores.
// 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]);
}
// ...
El split(";", 2)[0]
está allí para deshacerse de los atributos de galletas que son irrelevantes para el lado del servidor como expires
, path
, etc. Alternativamente, se podría también utilizar cookie.substring(0, cookie.indexOf(';'))
en lugar de split()
.
Modo de transmisión
Por HttpURLConnection
defecto, almacenará en el búfer todo el cuerpo de la solicitud antes de enviarlo, independientemente de si ha establecido una longitud de contenido fija usted mismo connection.setRequestProperty("Content-Length", contentLength);
. Esto puede causar OutOfMemoryException
correos electrónicos cada vez que envía solicitudes POST grandes (por ejemplo, cargando archivos). Para evitar esto, desea configurar el HttpURLConnection#setFixedLengthStreamingMode()
.
httpConnection.setFixedLengthStreamingMode(contentLength);
Pero si la longitud del contenido realmente no se conoce de antemano, entonces puede hacer uso del modo de transmisión fragmentada configurando en HttpURLConnection#setChunkedStreamingMode()
consecuencia. Esto establecerá el Transfer-Encoding
encabezado HTTP al chunked
que forzará el envío del cuerpo de la solicitud en fragmentos. El siguiente ejemplo enviará el cuerpo en trozos de 1 KB.
httpConnection.setChunkedStreamingMode(1024);
Agente de usuario
Puede suceder que una solicitud devuelva una respuesta inesperada, mientras funciona bien con un navegador web real . El lado del servidor probablemente esté bloqueando las solicitudes en función del User-Agent
encabezado de la solicitud. Por URLConnection
defecto, la establecerá en Java/1.6.0_19
donde la última parte es obviamente la versión JRE. Puede anular esto de la siguiente manera:
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.
Use la cadena de User-Agent de un navegador reciente .
Manejo de errores
Si el código de respuesta HTTP es 4nn
(Error del cliente) o 5nn
(Error del servidor), es posible que desee leer el HttpURLConnection#getErrorStream()
para ver si el servidor ha enviado información de error útil.
InputStream error = ((HttpURLConnection) connection).getErrorStream();
Si el código de respuesta HTTP es -1, entonces algo salió mal con la conexión y el manejo de la respuesta. La HttpURLConnection
implementación está en JRE anteriores algo defectuosos para mantener las conexiones vivas. Es posible que desee desactivarlo estableciendo la http.keepAlive
propiedad del sistema en false
. Puede hacer esto mediante programación al comienzo de su aplicación:
System.setProperty("http.keepAlive", "false");
Subiendo archivos
Normalmente usaría la multipart/form-data
codificación para contenido POST mixto (datos binarios y de caracteres). La codificación se describe con más detalle en 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 el otro lado es a HttpServlet
, entonces doPost()
se llamará a su método y las partes estarán disponibles por HttpServletRequest#getPart()
(¡nota, por lo tanto no,getParameter()
etc.!). El getPart()
método es, sin embargo relativamente nuevo, es introducido en Servlet 3.0 (Glassfish 3, Tomcat 7, etc). Antes de Servlet 3.0, su mejor opción es usar Apache Commons FileUpload para analizar una multipart/form-data
solicitud. Consulte también esta respuesta para ver ejemplos de los enfoques FileUpload y Servelt 3.0.
Manejo de sitios HTTPS no confiables o mal configurados
A veces necesita conectar una URL HTTPS, tal vez porque está escribiendo un raspador web. En ese caso, es probable que se enfrente javax.net.ssl.SSLException: Not trusted server certificate
a algunos sitios HTTPS que no mantienen sus certificados SSL actualizados, java.security.cert.CertificateException: No subject alternative DNS name matching [hostname] found
o javax.net.ssl.SSLProtocolException: handshake alert: unrecognized_name
a algunos sitios HTTPS mal configurados.
El siguiente static
inicializador de una sola vez en su clase de raspador web debería ser HttpsURLConnection
más indulgente con respecto a esos sitios HTTPS y, por lo tanto, ya no arrojará esas excepciones.
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);
}
}
Ultimas palabras
El Apatt HttpComponents HttpClient es mucho más conveniente en todo esto :)
Analizar y extraer HTML
Si todo lo que quieres es analizar y extraer datos de HTML, mejor usa un analizador HTML como Jsoup
Ask Question
botón en la parte superior derecha.--
parte no es parte del límite en sí. Es solo una cadena de separación. Revertí tu edición no válida.HttpClient
ahora yHttpURLConnection
es cruel. android-developers.blogspot.in/2011/09/…Cuando se trabaja con HTTP, casi siempre es más útil hacer referencia a ella
HttpURLConnection
que a la clase baseURLConnection
(ya queURLConnection
es una clase abstracta cuando se solicitaURLConnection.openConnection()
en una URL HTTP que es lo que obtendrá de todos modos).Luego, en lugar de confiar en
URLConnection#setDoOutput(true)
establecer implícitamente el método de solicitud en POST, puede hacer lohttpURLConnection.setRequestMethod("POST")
que algunos consideren más natural (y que también le permite especificar otros métodos de solicitud como PUT , DELETE , ...).También proporciona constantes HTTP útiles para que pueda hacer:
fuente
setDoOutput()
de lotrue
contrario, se generará una excepción (incluso si ustedsetRequestMethod("POST")
). Para ser claros: la configuraciónURLConnection#setDoOutput(true)
de establecertrue
implícitamente el método de solicitud en POST, pero la configuraciónhttpURLConnection.setRequestMethod("POST")
de POST no se establece implícitamentesetDoOutput()
entrue
.Inspirado por esta y otras preguntas sobre SO, he creado un cliente básico básico de código abierto http que incorpora la mayoría de las técnicas que se encuentran aquí.
google-http-java-client también es un excelente recurso de código abierto.
fuente
Le sugiero que eche un vistazo al código en kevinsawicki / http-request , es básicamente un contenedor
HttpUrlConnection
que proporciona una API mucho más simple en caso de que solo quiera hacer las solicitudes en este momento o puede consultar las fuentes ( no es demasiado grande) para ver cómo se manejan las conexiones.Ejemplo: realice una
GET
solicitud con tipo de contenidoapplication/json
y algunos parámetros de consulta:fuente
Hay 2 opciones a las que puede acceder con HTTP URL Hits: GET / POST
OBTENER Solicitud: -
Solicitud POSTAL: -
fuente
También me inspiró mucho esta respuesta.
A menudo estoy en proyectos en los que necesito hacer algo de HTTP, y es posible que no quiera traer muchas dependencias de terceros (que traen otros y así sucesivamente, etc.)
Comencé a escribir mis propias utilidades basadas en parte de esta conversación (no en ninguna parte):
Entonces solo hay un montón o métodos estáticos.
Luego publica ...
Bueno, ya captas la idea....
Aquí están las pruebas:
Puedes encontrar el resto aqui:
https://github.com/RichardHightower/boon
Mi objetivo es proporcionar las cosas comunes que uno quisiera hacer de una manera un poco más fácil que ...
fuente
doPost
método haya uncharset
parámetro, que se usa para establecer el encabezado de la solicitud, pero luego los datos se escriben con un conjunto de caracteres codificadoIO.CHARSET
. ¿Un insecto?Actualizar
En Java 9, puede enviar una
GET
solicitud como:Luego puede examinar el devuelto
HttpResponse
:Dado que este nuevo Cliente HTTP está en
java.httpclient
jdk.incubator.httpclient
módulo, debe declarar esta dependencia en sumodule-info.java
archivo:fuente
Inicialmente fui engañado por este artículo que favorece
HttpClient
.Más tarde me di cuenta de que
HttpURLConnection
este artículo se va a quedarSegún el blog de Google :
Después de leer este artículo y algunas otras preguntas de stack over flow, estoy convencido de que
HttpURLConnection
se quedará por más tiempo.Algunas de las preguntas SE favorecen
HttpURLConnections
:En Android, realice una solicitud POST con datos de formulario codificado de URL sin usar UrlEncodedFormEntity
HttpPost funciona en proyectos Java, no en Android
fuente
También está OkHttp , que es un cliente HTTP que es eficiente por defecto:
Primero cree una instancia de
OkHttpClient
:Luego, prepare su
GET
solicitud:finalmente, use
OkHttpClient
para enviar preparadoRequest
:Para más detalles, puede consultar la documentación de OkHttp
fuente
También puede usar
JdkRequest
desde jcabi-http (Soy un desarrollador), que hace todo este trabajo por usted, decorando HttpURLConnection, disparando solicitudes HTTP y analizando respuestas, por ejemplo:Consulte esta publicación de blog para obtener más información: http://www.yegor256.com/2014/04/11/jcabi-http-intro.html
fuente
si está utilizando http get, elimine esta línea
fuente