2010-02-21 2 views
8

Existe-t-il un moyen d'obtenir l'en-tête HTTP de réponse brute?Obtention d'en-têtes de réponse HTTP bruts

La méthode getHeaderField() ne fonctionne pas pour moi, car le serveur crache plusieurs 'Set-Cookie' et certains d'entre eux sont perdus.

+0

Il semble que vous utilisiez une bibliothèque comme Apache HTTP Client? Serait utile d'indiquer que si oui, puisque je suppose que vous demandez si cette bibliothèque particulière a une telle méthode. –

+0

Serait utile, mais je pense qu'il n'utilise pas le client apache mais la bibliothèque standard Java: http://docs.oracle.com/javase/6/docs/api/java/net/URLConnection.html#getHeaderField(java.lang. Chaîne) – thermz

Répondre

29

La méthode getHeaderField() ne fonctionne pas pour moi

Vous vous demandez dans le contexte de java.net.URLConnection, est-il? Non, l'obtention des en-têtes de réponse HTTP bruts n'est pas possible avec URLconnection. Vous devrez revenir à la programmation de bas niveau Socket. Voici un SSCCE, il suffit de le copier et le coller.

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

} 

Pour éviter SO surcharge par tout le monde essaie cet extrait, voici comment la sortie ressemblera:

 
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 

Pour en savoir plus sur l'envoi de requêtes HTTP la voie de bas niveau, lisez le HTTP specification.

Toutefois, vous souhaiterez probablement utiliser la méthode getHeaderFields() à la place pour récupérer un en-tête avec plusieurs valeurs. Le getHeaderField() renvoie uniquement la dernière valeur, selon le document API lié.

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

Heys dites-vous que 'java.net.URLConnection' est construit sur ces méthodes? – Pacerier

+0

"L'obtention des en-têtes de réponse HTTP bruts n'est pas possible avec' URLConnection' "? Que retourne 'getHeaderField (int)'? – erickson

+0

@erickson: il analyse les en-têtes de réponse brutes et renvoie la valeur de l'en-tête sur l'index donné. Il ne renvoie pas les en-têtes de réponse bruts exactement comme indiqué dans la citation dans ma réponse. Je crois que vous interprétez mal dans le contexte de cette question. Avez-vous d'ailleurs lu l'indice 'getHeaderFields()' au bas de ma réponse? Btw: Je n'ai pas downvote votre réponse :) – BalusC

2

Le plus simple est d'utiliser la méthode getHeaderFields() de URLConnection. Voici un code qui fait quelque chose d'équivalent.

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

Cette réponse est incorrecte? – Pacerier

+3

@Pacerier L'avez vous essayé? Qu'avez-vous trouvé être incorrect? – erickson

+0

Je reçois des en-têtes 'Set-Cookie' vides. Deux ou trois d'entre eux, selon ce que l'autre partie envoie. Les autres en-têtes fonctionnent bien. Le problème ne semble pas se situer dans l'impression car 'connection.getRequestProperties()' indique 'Set-Cookies = [,]'. Les cookies sont 'sécurisés; HTTPOnly', mais cela ne devrait pas avoir d'importance en Java. Étrange, n'est-ce pas? – maaartinus

6

Pas exactement 'brute' mais concise:

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

Si vous vous inquiétez que certains des en-têtes OBTIENNENT utilisation perdus:

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

PS: Mieux vaut tard que jamais. :)

+1

Je n'ai pas testé votre exemple, mais je pense que getHeaderFields renvoie une seule valeur pour un champ. Cela conduit à des problèmes, si vous obtenez plusieurs champs avec un nom égal, par exemple "Set-Cookies" est l'un d'entre eux. – p4553d

+2

@ p4553d - C'est pourquoi entrySet renvoie une liste comme valeur ... Me pense. – ostergaard

1

En retard à la fête, mais voici la solution la plus simple. Implémentez simplement CookieStore. (Ou utiliser l'implémentation par défaut et laissez-le prendre soin d'ajouter les cookies pour vos appels.)

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

Définissez votre magasin cookie en tant que gestionnaire de cookies par défaut

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

Et chaque nouveau cookie vous apparaîtra dans add() dans votre CookieStore. J'ai eu le même problème avec les paramètres étant écrasés en ayant le même nom "Set-Cookie" dans une seule demande, et maintenant je reçois à la fois le cookie et le sessionId.