2010-02-21 17 views
8

C'è un modo per ottenere l'intestazione http di risposta non elaborata?Ottenere intestazioni di risposta HTTP non corretti

Il metodo getHeaderField() non funziona per me, perché il server sputa più "Set-Cookie" e alcuni di essi vengono persi.

+0

Sembra che tu stia utilizzando una libreria come Apache HTTP Client? Sarebbe utile affermare che, in tal caso, poiché presumo che tu stia chiedendo se quella particolare biblioteca abbia un tale metodo. –

+0

Sarebbe utile, ma penso che non stia usando il client Apache ma la libreria standard Java: http://docs.oracle.com/javase/6/docs/api/java/net/URLConnection.html#getHeaderField(java.lang. String) – thermz

risposta

29

Il metodo getHeaderField() non funziona per me

Stai chiedendo questo nel contesto di java.net.URLConnection, è vero? No, non è possibile ottenere le intestazioni di risposta HTTP non elaborate con URLconnection. Dovrai tornare alla programmazione di livello basso Socket. Ecco un SSCCE, basta copiare e non rovinare.

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) {} 
     } 
    } 

} 

Per evitare in modo da essere sovraccaricati da tutti di provare questo frammento di codice, ecco come l'output sarà simile:

 
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 

Per ulteriori informazioni sull'invio richieste HTTP il modo di basso livello, leggere il HTTP specification.

Tuttavia, probabilmente si desidera utilizzare il metodo getHeaderFields() per recuperare un'intestazione con più valori. Il getHeaderField() vale a dire restituisce solo l'ultimo valore, come da documento API collegato.

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

Heys stai dicendo che 'java.net.URLConnection' è basato su questi metodi? – Pacerier

+0

"L'ottenimento delle intestazioni di risposta HTTP non è possibile con' URLConnection' "? Cosa restituisce 'getHeaderField (int)'? – erickson

+0

@erickson: analizza le intestazioni delle risposte non elaborate e restituisce il valore per l'intestazione dell'indice specificato. Non restituisce le intestazioni di risposta non elaborata esattamente come mostrato nella citazione nella mia risposta. Credo che tu stia interpretando erroneamente "crudo" nel contesto di questa domanda. Hai comunque letto il suggerimento "getHeaderFields()" in fondo alla mia risposta? A proposito: non ho votato in difetto la tua risposta :) – BalusC

2

Il modo più semplice è quello di utilizzare il metodo di URLConnectiongetHeaderFields(). Ecco un codice che fa qualcosa di 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

Questa risposta non è corretta vero? – Pacerier

+3

@Pacerier Hai provato? Cosa hai trovato sbagliato? – erickson

+0

Mi stanno svuotando le intestazioni 'Set-Cookie'. Due o tre di loro, a seconda di ciò che l'altra parte invia. Altre intestazioni funzionano bene. Il problema non sembra essere nella stampa poiché 'connection.getRequestProperties()' mostra 'Set-Cookies = [,]'. I cookie sono 'Sicuro; HTTPOnly', ma questo non dovrebbe importare in Java. Strano, non è vero? – maaartinus

6

Non esattamente 'crudo', ma conciso:

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

Se ti preoccupi che alcune delle intestazioni sono perdersi uso:

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

PS: Meglio tardi che mai. :)

+1

Non ho testato il tuo esempio, ma credo che getHeaderFields restituisca solo un valore per un campo. Questo porta a problemi, se ottieni più campi con lo stesso nome, ad esempio "Set-Cookies" è uno di questi. – p4553d

+2

@ p4553d - ecco perché entrySet restituisce un elenco come valore ... Io penso. – ostergaard

1

In ritardo per la festa, ma ecco la soluzione più semplice. Attua semplicemente CookieStore. (O utilizzare l'implementazione di default e lasciare che prendersi cura di aggiungere i cookie per le chiamate successive.)

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

impostare il proprio negozio di biscotto come gestore di cookie predefinito

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

E ogni nuovo cookie ti apparirà in add() nel tuo CookieStore. Ho avuto lo stesso problema con i param sovrascrivibili avendo lo stesso nome "Set-Cookie" in una singola richiesta, e ora ho sia il cookie che il sessionId.

Problemi correlati