首先来到php文档。已经说的很清楚了。
当 HTTP POST 请求的 Content-Type 是 application/x-www-form-urlencoded 或 multipart/form-data 时,会将变量以关联数组形式传入当前脚本。
所以python,请求的时候header中content-type需要是这2种。
index.php
<?php
$input = file_get_contents('php://input');
var_dump($input);//form-data 不走这里
var_dump($_POST);
form_data.py
from requests_toolbelt import MultipartEncoder
import requests
m = MultipartEncoder(fields={'field0': 'value', 'field1': '中文'})
print(m.to_string())
print(m.content_type)
m = MultipartEncoder(fields={'field0': 'value', 'field1': '中文'})
r = requests.post('http://127.0.0.1/index.php', data=m,
headers={'Content-Type': m.content_type})
print(r.content)
#返回值
b'--ea08f072980f44e4b9b1bf1c92831c9d\r\nContent-Disposition: form-data; name="field0"\r\n\r\nvalue\r\n--ea08f072980f44e4b9b1bf1c92831c9d\r\nContent-Disposition: form-data; name="field1"\r\n\r\n\xe4\xb8\xad\xe6\x96\x87\r\n--ea08f072980f44e4b9b1bf1c92831c9d--\r\n'
multipart/form-data; boundary=ea08f072980f44e4b9b1bf1c92831c9d
b'string(0) ""\narray(2) {\n ["field0"]=>\n string(5) "value"\n ["field1"]=>\n string(6) "\xe4\xb8\xad\xe6\x96\x87"\n}\n'
form_urlencoded.py
from socket import *
import urllib3
import urllib
import json
import struct
import time
import threading
import sys
import time
http = urllib3.PoolManager()
url = 'http://127.0.0.1/index.php'
info = {'field0': 'value', 'field1': '中文'}
print(json.dumps(info))
r = http.request('POST', url, body=json.dumps(info), headers={"Content-Type": "application/x-www-form-urlencoded"})
print(r.status)
print(r.data)
#返回值
{"field0": "value", "field1": "\u4e2d\u6587"}
200
b'string(45) "{"field0": "value", "field1": "\\u4e2d\\u6587"}"\narray(1) {\n ["{"field0":_"value",_"field1":_"\\u4e2d\\u6587"}"]=>\n string(0) ""\n}\n'
区别
对于请求数据
通过两组例子,你可以直观的看出来请求方式的区别,这里专门把form-data中的请求数据发出来
--ea08f072980f44e4b9b1bf1c92831c9d
Content-Disposition: form-data; name="field0"
value
--ea08f072980f44e4b9b1bf1c92831c9d
Content-Disposition: form-data; name="field1"
\xe4\xb8\xad\xe6\x96\x87
--ea08f072980f44e4b9b1bf1c92831c9d--
form-data被一串编码分割,这个分隔叫做boundary,我们在后面打印的m.content_type中可以看出,
multipart/form-data; boundary=ea08f072980f44e4b9b1bf1c92831c9d
Content-Type里多了boundary就是上面的分隔符。这种方式一般用来上传文件,各大服务端语言对它也有着良好的支持。
我们的例子不是很明显,这里提一下,application/x-www-form-urlencoded提交的数据按照 key1=val1&key2=val2 的方式进行编码,key 和 val 都进行了 URL 转码。
对于输出结果
我们发现form-data 没有走php://input
enctype="multipart/form-data" 的时候 php://input 是无效的。
如果把content-type换成text/html或者application/json我们在$_POST中返回就为空了,但是数据可以再php://input中获取到。