Đăng JSON bằng các yêu cầu Python


633

Tôi cần POST một JSON từ máy khách đến máy chủ. Tôi đang sử dụng Python 2.7.1 và Simplejson. Khách hàng đang sử dụng Yêu cầu. Máy chủ là CherryPy. Tôi có thể NHẬN một JSON được mã hóa cứng từ máy chủ (mã không được hiển thị), nhưng khi tôi cố gắng POST một JSON cho máy chủ, tôi nhận được "400 Yêu cầu xấu".

Đây là mã khách hàng của tôi:

data = {'sender':   'Alice',
    'receiver': 'Bob',
    'message':  'We did it!'}
data_json = simplejson.dumps(data)
payload = {'json_payload': data_json}
r = requests.post("http://localhost:8080", data=payload)

Đây là mã máy chủ.

class Root(object):

    def __init__(self, content):
        self.content = content
        print self.content  # this works

    exposed = True

    def GET(self):
        cherrypy.response.headers['Content-Type'] = 'application/json'
        return simplejson.dumps(self.content)

    def POST(self):
        self.content = simplejson.loads(cherrypy.request.body.read())

Có ý kiến ​​gì không?


Tôi đã sử dụng một phiên bản rút gọn của một ví dụ ra khỏi tài liệu .
Charles R

Nhận xét của tôi vẫn đứng vững - CherryPy không gọi __init__các phương thức lớp bằng một contentđối số (và không yêu cầu trong liên kết bạn cung cấp). Trong ví dụ chi tiết họ có, người dùng cung cấp mã gọi __init__và cung cấp các đối số mà chúng ta chưa thấy ở đây vì vậy tôi không biết đối tượng của bạn đang ở trạng thái nào khi # this worksbình luận của bạn có liên quan.
Nick Bastin

1
Bạn có yêu cầu xem dòng nơi tạo ra thể hiện không?
Charles R

vâng, tôi đã cố gắng bắt đầu ví dụ của bạn để kiểm tra nó, và tôi không chắc bạn đã bắt đầu nó như thế nào.
Nick Bastin

Mã đã thay đổi. Bây giờ tôi đang tạo ra nó mà không cần tranh luận thêm. cherrypy.quickstart(Root(), '/', conf).
Charles R

Câu trả lời:


1053

Kể từ phiên bản Yêu cầu 2.4.2 trở đi, bạn có thể sử dụng thay thế tham số 'json' trong cuộc gọi để đơn giản hơn.

>>> import requests
>>> r = requests.post('http://httpbin.org/post', json={"key": "value"})
>>> r.status_code
200
>>> r.json()
{'args': {},
 'data': '{"key": "value"}',
 'files': {},
 'form': {},
 'headers': {'Accept': '*/*',
             'Accept-Encoding': 'gzip, deflate',
             'Connection': 'close',
             'Content-Length': '16',
             'Content-Type': 'application/json',
             'Host': 'httpbin.org',
             'User-Agent': 'python-requests/2.4.3 CPython/3.4.0',
             'X-Request-Id': 'xx-xx-xx'},
 'json': {'key': 'value'},
 'origin': 'x.x.x.x',
 'url': 'http://httpbin.org/post'}

EDIT: Tính năng này đã được thêm vào tài liệu chính thức. Bạn có thể xem nó ở đây: Tài liệu yêu cầu


114
Tôi không thể tin được mình đã lãng phí bao nhiêu thời gian trước khi vấp phải câu trả lời của bạn. Các tài liệu yêu cầu cần được nâng cấp, hoàn toàn không có gì trên jsontham số. Tôi đã phải vào Github trước khi tôi thấy bất kỳ đề cập nào về nó: github.com/kennethreitz/requests/blob/
mẹo

1
Đặt câu trả lời này thành câu trả lời được chấp nhận vì điều này là thành ngữ hơn kể từ 2.4.2. Hãy nhớ rằng, đối với unicode điên, điều này có thể không hoạt động.
Charles R

Tôi đã ở trong đôi giày giống như @IAmKale. Điều này đã làm giảm bớt sự đau đầu mà tôi gặp phải với API Gateway của AWS. Nó yêu cầu dữ liệu POST theo định dạng JSON theo mặc định.
jstudios

1
Giống như một kẻ ngốc, tôi đã cố gắng sử dụng tham số dữ liệu với application / json loại nội dung :(
Toán tử bất hợp pháp

Tôi đã thấy một ví dụ về điều này đã lấy đối tượng dict và thực hiện json.dumps (đối tượng) trước khi gửi. Đừng làm điều này ... nó làm rối JSON của bạn. Ở trên là hoàn hảo..bạn có thể vượt qua nó một đối tượng trăn và nó biến thành json hoàn hảo.
MydKnight

376

Hóa ra tôi đã thiếu thông tin tiêu đề. Các công việc sau đây:

url = "http://localhost:8080"
data = {'sender': 'Alice', 'receiver': 'Bob', 'message': 'We did it!'}
headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}
r = requests.post(url, data=json.dumps(data), headers=headers)

Bắt tốt - Tôi thấy bạn application/jsonvào GETvà bằng cách nào đó đã bỏ lỡ rằng bạn đã không cung cấp nó theo yêu cầu. Bạn cũng có thể cần đảm bảo rằng bạn trả lại một cái gì đó từ POSThoặc bạn có thể nhận được một 500.
Nick Bastin

Dường như không cần thiết. Khi tôi in r, tôi nhận được <Response [200]>.
Charles R

Làm thế nào để tôi lấy json này ở phía máy chủ?
VaidAbhishek

r = request.get (' localhost: 8080' ) c = r.content result = simplejson.loads (c)
Charles R

1
Ít đầu lên trước khi sử dụng json.dumpsở đây. Các datatham số requestshoạt động tốt với từ điển. Không cần chuyển đổi thành một chuỗi.
Advait S

71

Từ các yêu cầu 2.4.2 ( https://pypi.python.org/pypi/requests ), tham số "json" được hỗ trợ. Không cần chỉ định "Loại nội dung". Vì vậy, phiên bản ngắn hơn:

requests.post('http://httpbin.org/post', json={'test': 'cheers'})

29

Cách tốt hơn là NIỀM TIN

url = "http://xxx.xxxx.xx"

datas = {"cardno":"6248889874650987","systemIdentify":"s08","sourceChannel": 12}

headers = {'Content-type': 'application/json'}

rsp = requests.post(url, json=datas, headers=headers)

18
các Content-type: application/jsonlà không cần thiết như json=đã gợi ý đó.
Moshe

1
@Moshe hoàn toàn đồng ý, nhưng để yêu cầu phiên bản mới hơn, ElSTERearch sever yêu cầu phải đặt Content-type
devesh

@Moshe, Nếu loại nội dung là gì text/html; charset=UTF-8. Sau đó, trên sẽ không làm việc?
Anu

2
" Cách tốt hơn là " không đăng câu trả lời SAU 3 năm sau khi có câu trả lời đúng. -1
CONvid19

3

Hoạt động hoàn hảo với python 3.5+

khách hàng

import requests
data = {'sender':   'Alice',
    'receiver': 'Bob',
    'message':  'We did it!'}
r = requests.post("http://localhost:8080", json={'json_payload': data})

người phục vụ:

class Root(object):

    def __init__(self, content):
        self.content = content
        print self.content  # this works

    exposed = True

    def GET(self):
        cherrypy.response.headers['Content-Type'] = 'application/json'
        return simplejson.dumps(self.content)

    @cherrypy.tools.json_in()
    @cherrypy.tools.json_out()
    def POST(self):
        self.content = cherrypy.request.json
        return {'status': 'success', 'message': 'updated'}

3

Nên sử dụng tham số nào giữa (data / json / files), nó thực sự phụ thuộc vào tiêu đề yêu cầu có tên ContentType (thường kiểm tra thông qua công cụ dành cho nhà phát triển của trình duyệt của bạn),

khi Kiểu nội dung là application / x-www-form-urlencoding, mã phải là:

requests.post(url, data=jsonObj)

khi Kiểu nội dung là ứng dụng / json, mã của bạn được coi là một trong những điều dưới đây:

requests.post(url, json=jsonObj)
requests.post(url, data=jsonstr, headers={"Content-Type":"application/json"})

khi Kiểu nội dung là nhiều dữ liệu / biểu mẫu, nó được sử dụng để tải lên các tệp, vì vậy mã của bạn phải là:

requests.post(url, files=xxxx)

Chúa ơi, cảm ơn bạn. Tôi đã hất tóc ra một lúc trước.
Vahagn Tumanyan

rất vui vì có thể giúp bạn :)
xiaoming
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.