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 đó.
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
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
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 *. –