2012-05-20 49 views
37

Khi tôi gửi một yêu cầu HTTP bình thường thông qua một ổ cắm, máy chủ không phản hồi bằng phản hồi OK. Tôi đã sao chép tiêu đề HTTP từ FireFox. Đây là mã:Gửi yêu cầu HTTP theo cách thủ công qua cổng

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

Tuy nhiên, đây là câu trả lời tôi nhận được:

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> 

Tôi biết rằng tôi có thể làm điều này bằng cách sử dụng URL.openStream(), nhưng tại sao máy chủ không xác định các yêu cầu HTTP khi tôi gửi nó bằng tay?

+3

Tôi nghĩ rằng bạn phải gửi một newline bổ sung sau khi tất cả các tiêu đề của bạn; 'pw.println();', và sử dụng 'println()' cho các tiêu đề là tốt? – Torious

+0

@Torious Yeah, đó là vấn đề. Cảm ơn :) –

+1

Và dòng mới phải có dạng \ r \ n cho HTTP. – EJP

Trả lời

37

Hai điều:

  1. Bạn nên sử dụng println thay vì print in mục của bạn để dòng riêng biệt.
  2. Yêu cầu HTTP phải kết thúc bằng một dòng trống (link). Vì vậy, hãy thêm pw.println("");
+0

Hoàn hảo. Việc thêm dòng trống là quan trọng! – asgs

+1

Tính năng này chỉ hoạt động trên các máy Windows. Trên Linux, nó sẽ chỉ in LF thay vì CRLF cần thiết cho đặc tả HTTP. Xem các câu trả lời khác. – Xiv

+0

tại sao nó đưa ra và 'HTTP/1.1 400 Yêu cầu Xấu 'khi tôi thay đổi máy chủ thành' pw.println ("Host: httpstackoverflow.com/questions/10673684/send-http-request-manually-via-socket"); ' – beginner

19

Bạn không theo dõi HTTP RFC.

  • Dòng tiêu đề luôn được kết thúc bằng CR LF (ví dụ: 0x0d cộng với 0x0a).
  • Tiêu đề kết thúc sau dòng mới kép đầu tiên. Trong trường hợp của bạn, bạn không bao gồm dấu dòng mới để máy chủ không nhận ra phần cuối của tiêu đề yêu cầu.

Nói chung, bạn nên luôn cố gắng sử dụng các thư viện HTTP hiện có. Mặc dù HTTP có vẻ là một giao thức đơn giản (và nó được so sánh với các giao thức khác), nó có các quy tắc ngữ pháp và ngữ nghĩa khá nghiêm ngặt. Nếu bạn tự mình thực hiện điều này, bạn nên đọc và hiểu các phần liên quan của RFC 2616 (và liên quan).

Đáng buồn thay, đã có quá nhiều triển khai HTTP không mong muốn không tuân theo các tiêu chuẩn hiện có khiến cuộc sống của mọi người trở nên khốn khổ. Tự khắc phục sự cố và sử dụng các thư viện HTTP của ngôn ngữ bạn đã chọn.

+1

+1 để nhận phần \ r \ n một phần. – EJP

4

Sửa lỗi sau, như đã đề cập trong các câu trả lời trước, giải quyết được vấn đề;

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

Việc sửa chữa đúng mà thực sự làm việc và nó là nền tảng chéo:

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

Tôi sử dụng 'Host:' thay vì 'Host:' và tất cả nhận được yêu cầu xấu (400) và phải mất một ngày để nhận ra rằng, nó thực sự sucks. –

Các vấn đề liên quan