2013-02-04 33 views
6

Cố gắng thực hiện yêu cầu POST giữa ứng dụng Python (WSGI) và ứng dụng NodeJS + Express. Chúng nằm trên các máy chủ khác nhau.Hành vi không nhất quán với các yêu cầu HTTP POST trong Python

Vấn đề là khi sử dụng các địa chỉ IP khác nhau (ví dụ: mạng riêng so với mạng công cộng), một yêu cầu urllib2 trên mạng công cộng thành công, nhưng các yêu cầu tương tự cho các mạng riêng không thành công với một 502 Bad Gateway hoặc URLError [32] Broken pipe.

Các urllib2 mã tôi đang sử dụng là:

req = urllib2.Request(url, "{'some':'data'}", {'Content-Type' : 'application/json; charset=utf-8'}) 

res = urllib2.urlopen(req) 

print f.read() 

Bây giờ, tôi cũng đã được mã hóa theo yêu cầu như thế này, sử dụng requests:

r = requests.post(url, headers = {'Content-Type' : 'application/json; charset=utf-8'}, data = "{'some':'data'}") 

print r.text 

Và nhận được một phản ứng 200 OK. Phương pháp thay thế này hoạt động cho cả hai mạng.

Tôi quan tâm đến việc tìm hiểu xem có cần thêm một số cấu hình nào cho yêu cầu urllib2 mà tôi không biết hoặc tôi cần xem xét một số cấu hình mạng có thể bị thiếu (Tôi không tin điều này là trường hợp, vì phương thức yêu cầu thay thế hoạt động, nhưng tôi chắc chắn có thể sai).

Bất kỳ đề xuất hoặc con trỏ nào với điều này sẽ được đánh giá cao. Cảm ơn!

+1

Nếu bạn so sánh các tiêu đề được gửi bởi hai tiêu đề, chúng sẽ không giống nhau. (Ví dụ, 'requests' mặc định là' Accept-Encoding: gzip, deflate, compress', trong khi 'urllib' thành' Accept-Encoding: identity'.) Ghi lại các header request với mỗi phiên bản, và phát lại chúng với server bằng cách sử dụng , ví dụ, 'nc' và xem nó phản ứng như thế nào.Hoặc một cái gì đó về các tiêu đề 'urllib2' gây ra lỗi 502, hoặc nó đang thực hiện một số loại chuyển hướng/etc. mà yêu cầu hiểu bởi urllib2 thì không. – abarnert

+0

Ngoài ra… nếu nó hoạt động với 'yêu cầu', có lý do gì mà bạn không thể sử dụng' yêu cầu' không? – abarnert

+2

Tài liệu cho ['urllib2.Request'] (http://docs.python.org/2/library/urllib2.html#urllib2.Request) cho biết rằng tham số * data * phải được mã hóa là * application/x- www-form-urlencoded *. –

Trả lời

3

Vấn đề ở đây là, như Austin Phillips chỉ ra data tham số, constructor của urllib2.Request 's:

có thể là một chuỗi xác định dữ liệu bổ sung để gửi đến máy chủ ... data phải là một bộ đệm trong tiêu chuẩn ứng dụng/x-www-form-urlencoded định dạng. Hàm urllib.urlencode() lấy một ánh xạ hoặc chuỗi 2-tuple và trả về một chuỗi ở định dạng này.

Bằng cách chuyển dữ liệu được mã hóa JSON thay vì dữ liệu được mã hóa url, bạn đang bối rối ở đâu đó.

Tuy nhiên, Request có một phương pháp add_data:

Đặt dữ liệu Yêu cầu dữ liệu. Điều này được bỏ qua bởi tất cả các trình xử lý ngoại trừ các trình xử lý HTTP - và ở đó nó phải là một chuỗi byte và sẽ thay đổi yêu cầu thành POST thay vì GET.

Nếu bạn sử dụng điều này, bạn cũng nên sử dụng add_header thay vì chuyển nó vào hàm tạo, mặc dù dường như không được đề cập cụ thể ở bất kỳ đâu trong tài liệu.

Vì vậy, điều này sẽ làm việc:

req = urllib2.Request(url) 
req.add_data("{'some':'data'}") 
req.add_header('Content-Type', 'application/json; charset=utf-8') 
res = urllib2.urlopen(req) 

Trong một bình luận, bạn nói:

Lý do tôi không muốn chỉ là chuyển sang yêu cầu mà không tìm ra lý do tại sao Tôi thấy vấn đề này là có thể có một số vấn đề cơ bản sâu hơn mà điểm này có thể trở lại và gây ra các vấn đề khó phát hiện sau này.

Nếu bạn muốn tìm các vấn đề cơ bản sâu, bạn sẽ không làm điều đó bằng cách chỉ nhìn vào nguồn phía khách hàng của bạn. Bước đầu tiên để tìm ra "Tại sao X lại hoạt động nhưng Y không thành công?" với mã mạng là để tìm ra chính xác những gì byte X và Y từng gửi. Sau đó, bạn có thể cố gắng thu hẹp sự khác biệt có liên quan là gì và sau đó tìm ra phần nào của mã của bạn đang khiến Y gửi sai dữ liệu ở vị trí thích hợp.

Bạn có thể thực hiện việc này bằng cách ghi lại mọi thứ tại dịch vụ (nếu bạn kiểm soát), chạy Wireshark, v.v., nhưng cách dễ nhất, đối với các trường hợp đơn giản, là netcat. Bạn sẽ cần đọc man nc cho hệ thống của mình (và, trên Windows, bạn sẽ cần phải cài đặt và cài đặt netcat trước khi có thể chạy), vì cú pháp khác nhau cho mỗi phiên bản, nhưng nó luôn đơn giản như nc -kl 12345. Sau đó, trong ứng dụng khách của bạn, hãy thay đổi URL để sử dụng localhost:12345 thay cho tên máy chủ và nó sẽ kết nối với netcat và gửi yêu cầu HTTP của nó, nó sẽ được bán cho thiết bị đầu cuối. Sau đó, bạn có thể sao chép và sử dụng nc HOST 80 và dán nó để xem máy chủ thực sự phản hồi như thế nào và sử dụng nó để thu hẹp vị trí của vấn đề. Hoặc, nếu bạn gặp khó khăn, ít nhất bạn có thể sao chép và dán dữ liệu vào câu hỏi SO của bạn.


Một điều cuối cùng: Đây là gần như chắc chắn không liên quan đến vấn đề của bạn (vì bạn đang gửi dữ liệu chính xác cùng với requests và nó làm việc), nhưng dữ liệu của bạn là không thực sự hợp lệ JSON, bởi vì nó sử dụng đơn báo giá thay vì dấu ngoặc kép. Theo the docs, string được định nghĩa là:

string 
    "" 
    " chars " 

(. Các tài liệu có một đại diện đồ họa đẹp cũng)

Nói chung, trừ trường hợp thử nghiệm thực sự đơn giản, bạn không muốn viết JSON bằng tay. Trong nhiều trường hợp (bao gồm cả trường hợp của bạn), tất cả những gì bạn phải làm là thay thế "…" bằng json.dumps(…), vì vậy đây không phải là một khó khăn nghiêm trọng. Vì vậy:

req = urllib2.Request(url) 
req.add_data(json.dumps({'some':'data'})) 
req.add_header('Content-Type', 'application/json; charset=utf-8') 
res = urllib2.urlopen(req) 

Vì vậy, tại sao nó hoạt động? Vâng, trong JavaScript, các chuỗi được trích dẫn một cách hợp pháp, cũng như các thứ khác như dấu gạch chéo ngược không hợp lệ trong JSON và bất kỳ mã JS nào sử dụng eval bị hạn chế (hoặc tệ hơn, thô) để phân tích cú pháp sẽ chấp nhận nó . Và, bởi vì rất nhiều người đã quen với việc viết JSON xấu vì điều này, nhiều trình phân tích cú pháp JSON gốc của nhiều trình duyệt và nhiều thư viện JSON bằng các ngôn ngữ khác có cách giải quyết để cho phép các lỗi phổ biến. Nhưng bạn không nên dựa vào điều đó.

+0

Câu trả lời hay. Mẹo 'netcat' rất hữu ích và tôi sẽ ghi nhớ nó để sử dụng trong tương lai. Tôi sử dụng 'json.dumps' cho mã thực sự của mình, nhưng tôi đã bỏ nó ra để giảm kích thước câu hỏi. Tuy nhiên, đó là một quan sát rất tốt và tôi sẽ ghi nhớ nó để sử dụng trong tương lai. Cảm ơn rất nhiều. –

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