2010-02-21 28 views
8

¿Hay alguna forma de obtener el encabezado http de respuesta sin procesar?Obtención de encabezados de respuesta HTTP sin formato

El método getHeaderField() no funciona para mí, porque el servidor escupe múltiples 'Set-Cookie' y algunos se pierden.

+0

Parece que está utilizando una biblioteca como Apache HTTP Client? Sería útil indicarlo en caso afirmativo, ya que supongo que está preguntando si esa biblioteca en particular tiene dicho método. –

+0

Sería útil, pero creo que no está utilizando el cliente de Apache sino la biblioteca estándar de Java: http://docs.oracle.com/javase/6/docs/api/java/net/URLConnection.html#getHeaderField(java.lang. String) – thermz

Respuesta

29

getHeaderField() El método no funciona para mí

Estás haciendo esto en el contexto de java.net.URLConnection, ¿verdad? No, la obtención de los encabezados de respuesta HTTP sin formato no es posible con URLconnection. Tendrá que recurrir a la programación de bajo nivel de Socket. Aquí hay un SSCCE, solo copielo para pegarlo.

package com.stackoverflow.q2307291; 

import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.InputStreamReader; 
import java.io.OutputStreamWriter; 
import java.io.PrintWriter; 
import java.net.Socket; 

public class Test { 

    public static void main(String[] args) throws IOException { 
     String hostname = "stackoverflow.com"; 
     int port = 80; 

     Socket socket = null; 
     PrintWriter writer = null; 
     BufferedReader reader = null; 

     try { 
      socket = new Socket(hostname, port); 
      writer = new PrintWriter(new OutputStreamWriter(socket.getOutputStream())); 
      writer.println("GET/HTTP/1.1"); 
      writer.println("Host: " + hostname); 
      writer.println("Accept: */*"); 
      writer.println("User-Agent: Java"); // Be honest. 
      writer.println(""); // Important, else the server will expect that there's more into the request. 
      writer.flush(); 

      reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); 
      for (String line; (line = reader.readLine()) != null;) { 
       if (line.isEmpty()) break; // Stop when headers are completed. We're not interested in all the HTML. 
       System.out.println(line); 
      } 
     } finally { 
      if (reader != null) try { reader.close(); } catch (IOException logOrIgnore) {} 
      if (writer != null) { writer.close(); } 
      if (socket != null) try { socket.close(); } catch (IOException logOrIgnore) {} 
     } 
    } 

} 

evitar para ser sobrecargado por todo el mundo tratando este fragmento, así es como la salida se verá así:

 
HTTP/1.1 200 OK 
Cache-Control: private 
Content-Type: text/html; charset=utf-8 
Expires: Sun, 21 Feb 2010 20:39:08 GMT 
Server: Microsoft-IIS/7.5 
Date: Sun, 21 Feb 2010 20:39:07 GMT 
Connection: close 
Content-Length: 208969 

Para obtener más información sobre el envío de peticiones HTTP el camino de bajo nivel, leer el HTTP specification.

Sin embargo, probablemente desee utilizar el método getHeaderFields() para recuperar un encabezado con varios valores. El getHeaderField() solo devuelve el último valor, según el documento API vinculado.

List<String> cookies = connection.getHeaderFields().get("Set-Cookie"); 
+0

¿Estás diciendo que 'java.net.URLConnection' se basa en estos métodos? – Pacerier

+0

"La obtención de los encabezados de respuesta HTTP sin formato no es posible con' URLConnection' "? ¿Qué devuelve 'getHeaderField (int)'? – erickson

+0

@erickson: analiza los encabezados de respuesta sin procesar y devuelve el valor para el encabezado en el índice dado. No devuelve los encabezados de respuesta sin formato exactamente como se muestra en la cita en mi respuesta. Creo que está malinterpretando "en bruto" en el contexto de esta pregunta. Por cierto, ¿has leído la pista 'getHeaderFields()' en la parte inferior de mi respuesta? Por cierto: no rechacé tu respuesta :) – BalusC

2

La manera más fácil es utilizar el método de URLConnectiongetHeaderFields(). Aquí hay un código que hace algo equivalente.

static String[] getHeaders(HttpURLConnection con, String header) { 
    List<String> values = new ArrayList<String>(); 
    int idx = (con.getHeaderFieldKey(0) == null) ? 1 : 0; 
    while (true) { 
    String key = con.getHeaderFieldKey(idx); 
    if (key == null) 
     break; 
    if (header.equalsIgnoreCase(key)) 
     values.add(con.getHeaderField(idx)); 
    ++idx; 
    } 
    return values.toArray(new String[values.size()]); 
} 
+0

Esta respuesta no es correcta ¿verdad? – Pacerier

+3

@Pacerier ¿Lo has probado? ¿Qué encontraste para ser incorrecto? – erickson

+0

Obtengo encabezados 'Set-Cookie' vacíos. Dos o tres de ellos, dependiendo de lo que la otra parte envíe. Otros encabezados funcionan bien. El problema no parece residir en la impresión ya que 'connection.getRequestProperties()' muestra 'Set-Cookies = [,]'. Las cookies son 'Seguras; HTTPOnly', pero esto no debería importar en Java. Extraño, ¿verdad? – maaartinus

6

No exactamente 'en bruto', pero concisa:

for (Map.Entry<String, List<String>> k : myHttpURLConnection.getHeaderFields().entrySet()) { 
    System.out.println(k.toString()); 
} 

si usted se preocupa que algunas de las cabeceras están consiguiendo utilización perdido:

for (Map.Entry<String, List<String>> k : myHttpURLConnection.getHeaderFields().entrySet()) { 
    for (String v : k.getValue()){ 
     System.out.println(k.getKey() + ":" + v); 
    } 
} 

PS: Mejor tarde que nunca. :)

+1

No probé su ejemplo, pero creo que getHeaderFields devuelve solo un valor para un campo. Esto genera problemas, si obtiene múltiples campos con el mismo nombre, por ejemplo "Set-Cookies" es uno de ellos. – p4553d

+2

@ p4553d - es por eso que entrySet devuelve una lista como el valor ... Me piensa. – ostergaard

1

Tarde para la fiesta, pero aquí está la solución más simple. Solo implemente CookieStore. (O utilizar la implementación predeterminada y dejar que se ocupe de la adición de los cookies a las llamadas posteriores.)

http://docs.oracle.com/javase/7/docs/api/java/net/CookieStore.html

Indica tu tienda de galletas como el administrador de cookies por defecto

CookieManager cookieManager = new CookieManager(new MyCookieStore(), CookiePolicy.ACCEPT_ALL); 
CookieHandler.setDefault(cookieManager); 

Y cada nueva cookie aparecerá en add() en su CookieStore. Tuve el mismo problema con los parámetros que se sobreescriben al tener el mismo nombre "Set-Cookie" en una sola solicitud, y ahora obtengo tanto la cookie como la sessionId.

Cuestiones relacionadas