2012-05-20 45 views
37

Cuando envío una solicitud HTTP normal a través de un socket, el servidor no responde con una respuesta OK. Copié el encabezado HTTP de FireFox. Aquí está el código:Enviar solicitud HTTP manualmente a través del socket

Socket s = new Socket(InetAddress.getByName("stackoverflow.com"), 80); 
PrintWriter pw = new PrintWriter(s.getOutputStream()); 
pw.print("GET/HTTP/1.1"); 
pw.print("Host: stackoverflow.com"); 
pw.flush(); 
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream())); 
String t; 
while((t = br.readLine()) != null) System.out.println(t); 
br.close(); 

Sin embargo, aquí está la respuesta que recibí:

HTTP/1.0 408 Request Time-out 
Cache-Control: no-cache 
Connection: close 
Content-Type: text/html 

<html><body><h1>408 Request Time-out</h1> 
Your browser didn't send a complete request in time. 
</body></html> 

Sé que puedo hacer esto mediante el uso de URL.openStream(), pero ¿por qué el servidor no identifica la petición HTTP cuando lo envío manualmente?

+3

yo creo que hay que enviar un salto de línea adicional después de todas sus cabeceras; 'pw.println();', y use 'println()' para los encabezados también? – Torious

+0

@Torious Sí, ese es el problema. Gracias :) –

+1

Y las líneas nuevas deben ser de la forma \ r \ n para HTTP. – EJP

Respuesta

37

dos cosas:

  1. Debe utilizar println en lugar de print para imprimir sus entradas para separar las líneas.
  2. La solicitud HTTP debe finalizar en una línea en blanco (link). Así que agrega pw.println("");
+0

Perfecto. ¡Agregar la línea en blanco es importante! – asgs

+1

Esto solo funciona en máquinas con Windows. En Linux, solo imprimirá LF en lugar de CRLF, que es necesario para la especificación HTTP. Ver las otras respuestas – Xiv

+0

¿por qué da y 'HTTP/1.1 400 Bad Request' cuando cambié el host a' pw.println ("Host: httpstackoverflow.com/questions/10673684/send-http-request-manually-via-socket"); ' – beginner

19

No sigues el HTTP RFC.

  • líneas de cabecera siempre se terminan por un LF CR (es decir 0x0d más 0x0a).
  • El encabezado termina después de la primera doble línea nueva. En su caso, no incluye la nueva línea final para que el servidor no reconozca el final de los encabezados de solicitud.

Por lo general, siempre debe intentar utilizar las bibliotecas HTTP existentes. Aunque HTTP parece ser un protocolo simple (y se lo compara con otros), tiene reglas semánticas y sintácticas bastante estrictas. Si intenta implementarlo usted mismo, debería haber leído y entendido las partes relevantes de RFC 2616 (y relacionadas).

Lamentablemente, ya hay demasiadas implementaciones HTTP defectuosas que no siguen los estándares que hacen la vida imposible para todos. Ahórrese la molestia y use las bibliotecas HTTP del idioma elegido.

+1

+1 para obtener la parte \ r \ n correcta. – EJP

4

La solución siguiente, como se menciona en las respuestas anteriores, resuelve el problema;

pw.print("GET/HTTP/1.1\n\r\n"); 
pw.print("Host: stackoverflow.com\n\r\n"); 
8

La solución correcta, que realmente funciona y es multiplataforma:

pw.print("GET/HTTP/1.1\r\n"); 
    pw.print("Host: stackoverflow.com\r\n\r\n"); 
+0

Usé 'Host:' en lugar de 'Host ::' y todas obtuvieron Bad Request (400) y me llevó un día darme cuenta de que realmente apesta. –

Cuestiones relacionadas