2012-05-20 17 views
37

Kiedy wysyłam normalne żądanie HTTP przez gniazdo, serwer nie odpowiada odpowiedzią OK. Skopiowałem nagłówek HTTP z FireFox. Oto kod:Wyślij żądanie HTTP ręcznie za pomocą gniazda

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(); 

Jednak tutaj jest odpowiedź otrzymałem:

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> 

wiem, że mogę to zrobić za pomocą URL.openStream(), ale dlaczego serwer nie identyfikują żądania HTTP kiedy wysyłam go ręcznie?

+3

Chyba trzeba wysłać dodatkowe przełamane po wszystkich nagłówków; 'pw.println();' i używają 'println()' również dla nagłówków? – Torious

+0

@Torious Tak, to jest problem. Dzięki :) –

+1

A nowe linie muszą mieć format \ r \ n dla HTTP. – EJP

Odpowiedz

37

dwie rzeczy:

  1. należy użyć println zamiast print drukować swoje dane, aby oddzielić linie.
  2. Żądanie HTTP powinno kończyć się pustą linią (link). Dodaj więc pw.println("");
+0

Idealny. Dodawanie pustej linii jest ważne! – asgs

+1

Działa to tylko na komputerach z systemem Windows. W systemie Linux wydrukuje tylko LF zamiast CRLF, który jest potrzebny dla specyfikacji HTTP. Zobacz inne odpowiedzi. – Xiv

+0

dlaczego daje i "Złe żądanie HTTP/1.1 400" kiedy zmieniłem hosta na 'pw.println (" Host: httpstackoverflow.com/questions/10673684/send-http-request-manually-via-socket "); ' – beginner

19

Nie postępuj zgodnie z HTTP RFC.

  • rury rozgałęźnej są zawsze zakończona CR LF (tj 0x0d oraz 0x0a).
  • Nagłówek kończy się po pierwszym podwójnym znaku nowej linii. W twoim przypadku nie dodajesz końcowego znaku nowej linii, aby serwer nie rozpoznał końca nagłówków żądania.

Generalnie należy zawsze próbować korzystać z istniejących bibliotek HTTP. Chociaż HTTP wydaje się być prostym protokołem (i jest porównywany do innych), ma raczej ścisłe reguły syntaktyczne i semantyczne. Jeśli spróbujesz zaimplementować to samodzielnie, powinieneś przeczytać i zrozumieć odpowiednie części RFC 2616 (i powiązane).

Niestety, jest już zbyt wiele nieudolnych implementacji HTTP, które nie przestrzegają standardów, czyniąc życie dla wszystkich nieszczęśliwymi. Oszczędzaj sobie kłopotów i korzystaj z bibliotek HTTP wybranego języka.

+1

+1 za uzyskanie części \ r \ n prawej. – EJP

4

Następująca poprawka, o której mowa w poprzednich odpowiedziach, rozwiązuje problem;

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

Prawidłowe ustalenie, które naprawdę działa i jest wieloplatformowym:

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

Użyłem 'Host:' zamiast 'Host:' i wszystkich otrzymujących Bad Request (400) i zajęło to dzień, aby zrozumieć, że to naprawdę jest do bani. –

Powiązane problemy