โพสต์ JSON โดยใช้คำขอ Python


633

ฉันต้องการโพสต์ JSON จากไคลเอนต์ไปยังเซิร์ฟเวอร์ ฉันใช้ Python 2.7.1 และ simplejson ลูกค้ากำลังใช้คำขอ เซิร์ฟเวอร์คือ CherryPy ฉันสามารถรับ JSON แบบฮาร์ดโค้ดจากเซิร์ฟเวอร์ (ไม่แสดงรหัส) แต่เมื่อฉันพยายามที่จะโพสต์ JSON ไปยังเซิร์ฟเวอร์ฉันได้รับ "400 คำขอไม่ถูกต้อง"

นี่คือรหัสลูกค้าของฉัน:

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)

นี่คือรหัสเซิร์ฟเวอร์

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

ความคิดใด ๆ


ฉันใช้ตัวอย่างเวอร์ชันที่แยกออกมาจากเอกสารโดยตรง
Charles R

ความคิดเห็นของฉันยังคงมีอยู่ - CherryPy ไม่ได้เรียก__init__วิธีการเรียนพร้อมcontentอาร์กิวเมนต์ (และไม่ได้อ้างสิทธิ์ในลิงก์ที่คุณให้) ในตัวอย่างโดยละเอียดพวกเขามีผู้ใช้รหัสที่โทร__init__และให้ข้อโต้แย้งซึ่งเราไม่ได้เห็นที่นี่ดังนั้นฉันจึงไม่ทราบว่าวัตถุของคุณอยู่ในเมื่อ# this worksความคิดเห็นของคุณมีความเกี่ยวข้อง
Nick Bastin

1
คุณขอให้ดูบรรทัดที่สร้างอินสแตนซ์หรือไม่
ชาร์ลส์ R

ใช่ฉันพยายามที่จะเริ่มต้นตัวอย่างของคุณเพื่อทดสอบและฉันไม่แน่ใจว่าคุณเป็นคนยกตัวอย่างได้อย่างไร
Nick Bastin

รหัสมีการเปลี่ยนแปลง ตอนนี้ฉันกำลังสร้างมันโดยไม่มีข้อโต้แย้งเพิ่มเติม cherrypy.quickstart(Root(), '/', conf).
ชาร์ลส์อาร์

คำตอบ:


1053

ตั้งแต่ Requests เวอร์ชั่น 2.4.2 ขึ้นไปคุณสามารถใช้พารามิเตอร์ 'json' ในการโทรซึ่งจะทำให้ง่ายขึ้น

>>> 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'}

แก้ไข: คุณสมบัตินี้ได้รับการเพิ่มลงในเอกสารอย่างเป็นทางการ คุณสามารถดูได้ที่นี่: ขอเอกสาร


114
ฉันไม่อยากจะเชื่อเลยว่าฉันเสียเวลาไปมากแค่ไหนก่อนจะสะดุดกับคำตอบของคุณ ร้องขอเอกสารจะต้องมีการอัพเกรดไม่มีอะไรแน่นอนในjsonพารามิเตอร์ ฉันต้องไปที่ Github ก่อนที่จะเห็นการพูดถึง: github.com/kennethreitz/requests/blob/ …
IAmKale

1
การตั้งค่านี้เป็นคำตอบที่ยอมรับเนื่องจากนี่เป็นสำนวนที่เป็นไปได้มากขึ้นจาก 2.4.2 โปรดจำไว้ว่าสำหรับ Unicode บ้านี่อาจไม่ทำงาน
ชาร์ลส์อาร์

ฉันอยู่ในรองเท้าเดียวกับ @IAmKale สิ่งนี้ช่วยบรรเทาอาการปวดหัวของฉันได้ด้วยเกตเวย์ API ของ AWS มันต้องการข้อมูล POST ในรูปแบบ JSON โดยค่าเริ่มต้น
jstudios

1
เหมือนคนโง่ฉันพยายามใช้ data data กับ application / json ประเภทเนื้อหา :(
Illegal Operator

ฉันเห็นตัวอย่างของสิ่งนี้ที่นำวัตถุ dict และดำเนินการ json.dumps (วัตถุ) ก่อนส่ง อย่าทำสิ่งนี้ ... มันทำให้ JSON ของคุณเสีย ข้างบนนั้นสมบูรณ์แบบ .. คุณสามารถผ่านมันไปเป็นวัตถุหลามได้
MydKnight

376

ปรากฎว่าฉันขาดข้อมูลส่วนหัว ผลงานดังต่อไปนี้:

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)

จับดี - ผมเห็นคุณapplication/jsonในGETและพลาดอย่างใดที่คุณไม่ได้ให้มาในการร้องขอ นอกจากนี้คุณยังอาจต้องให้แน่ใจว่าคุณกลับมาจากบางสิ่งบางอย่างหรือคุณอาจได้รับPOST 500
Nick Bastin

ดูเหมือนจะไม่จำเป็น เมื่อฉันพิมพ์ฉันได้รับr <Response [200]>
ชาร์ลส์อาร์

ฉันจะเรียก json นี้ที่ฝั่งเซิร์ฟเวอร์ได้อย่างไร
VaidAbhishek

r = requests.get (' localhost: 8080' ) c = r.content result = simplejson.loads (c)
ชาร์ลส์อาร์

1
หัวน้อยก่อนใช้json.dumpsที่นี่ dataพารามิเตอร์ของrequestsผลงานได้ดีกับพจนานุกรม ไม่จำเป็นต้องแปลงเป็นสตริง
Advait S

71

จากคำขอ 2.4.2 ( https://pypi.python.org/pypi/requests ) สนับสนุนพารามิเตอร์ "json" ไม่จำเป็นต้องระบุ "ประเภทเนื้อหา" ดังนั้นเวอร์ชันที่สั้นกว่า:

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

29

วิธีที่ดีกว่าคือ:

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
Content-type: application/jsonซ้ำซ้อนเป็นjson=คำแนะนำที่ดีอยู่แล้วว่า
Moshe

1
@Moshe เห็นด้วยอย่างยิ่ง แต่จะขอรุ่นใหม่กว่า Elasticsearch ตัดต้องตั้ง Content-type
1225

@Moshe, text/html; charset=UTF-8เกิดอะไรขึ้นถ้าชนิดของเนื้อหาคือ ถ้าอย่างนั้นข้างบนจะไม่ทำงาน?
Anu

2
" วิธีที่ดีกว่าคือ " อย่าโพสต์ คำตอบที่ ไม่ถูกต้อง3 ปีหลังจากคำตอบที่ถูกต้อง -1
CONVid19

3

ทำงานได้อย่างสมบูรณ์แบบด้วย python 3.5+

ลูกค้า:

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

เซิร์ฟเวอร์:

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

ควรใช้พารามิเตอร์ใดระหว่าง (data / json / files) ขึ้นอยู่กับส่วนหัวคำขอที่ชื่อ ContentType (โดยปกติจะตรวจสอบผ่านเครื่องมือพัฒนาของเบราว์เซอร์ของคุณ)

เมื่อ Content-Type เป็นแอพพลิเคชั่น / x-www-form-urlencoded รหัสควรเป็น:

requests.post(url, data=jsonObj)

เมื่อ Content-Type เป็น application / json รหัสของคุณควรจะเป็นหนึ่งในด้านล่าง:

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

เมื่อ Content-Type เป็นแบบหลายส่วน / แบบฟอร์มข้อมูลจะใช้ในการอัปโหลดไฟล์ดังนั้นรหัสของคุณควรเป็น:

requests.post(url, files=xxxx)

พระเยซูคริสต์ขอบคุณ เมื่อไม่นานมานี้ผมกำลังสั่นเทา
Vahagn Tumanyan

ดีใจที่สามารถช่วยคุณได้
:)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.