Form表单的格式和Python Requests库的表单应用

在对接某第三方平台api时,postman测试form表单请求ok,但用python的requests库post请求,传参到data则请求失败,用flask搭了一个server测试两种请求都ok,打印body发现,一个Content-Type=application/x-www-form-urlencoded 而另一个Content-Type=multipart/form-data,猜测跟这个有关,但requests库中没有记得哪里设置这个参,查资料后,用requests库的files解决了,基于此,把requests的源码和form表单的请求也一并梳理了一下

Form表单再学习

Form表单常用于post请求中的body中,其实get中也能用,get和post除了method不同,其他到没有什么区别,不过还是要根据restful风格来使用

编码格式:

三种编码格式如下,html中使用enctype配置。
application/x-www-form-urlencoded: 窗体数据被编码为名称/值对,不能传文件
multipart/form-data: 窗体数据被编码为一条消息,页上的每个控件对应消息中的一个部分,可以传文件
Raw: 包括text/plain;application/json;text/html;application/xml等,服务端根据类型格式化数据

在postman中用这三种格式的数据请求一下看看请求包
x-www-form-urlencoded

POST /data/test HTTP/1.1
User-Agent: PostmanRuntime/7.28.4
Accept: */*
Postman-Token: 8a01749e-6aa6-4ea8-b7f3-23d5e0834a35
Host: www.test.com
Accept-Encoding: gzip, deflate, br
Content-Type: application/x-www-form-urlencoded
Content-Length: 15
Cookie: session=6db579aa-d66d-4093-b5e9-f0faf3590eab
Connection: keep-alive

test1=1&test2=2

form-data

POST /data/test HTTP/1.1
User-Agent: PostmanRuntime/7.28.4
Accept: */*
Postman-Token: 374e71ac-91d3-4f1a-a9a0-ec88747c2d8e
Host: www.test.com
Accept-Encoding: gzip, deflate, br
Content-Type: multipart/form-data; boundary=--------------------------941191091587600179800452
Cookie: session=6db579aa-d66d-4093-b5e9-f0faf3590eab
Content-Length: 267
Connection: keep-alive

----------------------------941191091587600179800452
Content-Disposition: form-data; name="test"

t1
----------------------------941191091587600179800452
Content-Disposition: form-data; name="test2"

t2
----------------------------941191091587600179800452--

Raw中的application/json,body中写什么就传什么,各种Content-Type在body中都一样,解析的时候按照各自的格式解析

POST /data/test HTTP/1.1
Content-Type: application/json
User-Agent: PostmanRuntime/7.28.4
Accept: */*
Postman-Token: 7f2ac6fd-7c79-403b-bb44-30091e22c5d5
Host: www.test.com
Accept-Encoding: gzip, deflate, br
Content-Length: 50
Cookie: session=6db579aa-d66d-4093-b5e9-f0faf3590eab
Connection: keep-alive

{
    "test": "t1",
    "test2": "t2"
}

Python Requests库中对Form表单的支持

找到requests库中post请求(代码注释都做了精简)

# .../site-packages/requests/api.py

def post(url, data=None, json=None, **kwargs):
    return request('post', url, data=data, json=json, **kwargs)

def request(method, url, **kwargs):
    """
    ......
    :param data: (optional) Dictionary, list of tuples, bytes, or file-like object to send in the body of the :class:`Request`.
    :param json: (optional) A JSON serializable Python object to send in the body of the :class:`Request`.
    :param files: (optional) Dictionary of ``'name': file-like-objects`` (or ``{'name': file-tuple}``) for multipart encoding upload.``file-tuple`` can be a 2-tuple ``('filename', fileobj)``, 3-tuple ``('filename', fileobj, 'content_type')`` or a 4-tuple ``('filename', fileobj, 'content_type', custom_headers)``, where ``'content-type'`` is a string defining the content type of the given file and ``custom_headers`` a dict-like object containing additional headers to add for the file.
    ......

用requests库操作请求看一下请求包

>>>from requests import post
>>>url = "http://www.test.com/data/test"
>>>data = {'test1': 't1', 'test2':'t2'}
>>>post(url, data=data)

POST /data/test HTTP/1.1
Host: www.test.com
User-Agent: python-requests/2.23.0
Accept-Encoding: gzip, deflate
Accept: */*
Content-Length: 17
Content-Type: application/x-www-form-urlencoded
Connection: keep-alive

test1=t1&test2=t2

可以看出来data参数用的是application/x-www-form-urlencoded格式

>>>post(url, json=data)

POST /data/test HTTP/1.1
Host: www.test.com
User-Agent: python-requests/2.23.0
Accept-Encoding: gzip, deflate
Accept: */*
Content-Length: 30
Content-Type: application/json
Connection: keep-alive

{"test1": "t1", "test2": "t2"}

json参数用的是Raw的application/json

>>>with open("log.log", 'r') as fp:
>>>    post(url, files={'file':fp})

POST /data/test HTTP/1.1
Host: www.test.com
User-Agent: python-requests/2.23.0
Accept-Encoding: gzip, deflate
Accept: */*
Content-Length: 169
Content-Type: multipart/form-data; boundary=374728dd2dd454ca341f3bcdc4cee913
Connection: keep-alive

--374728dd2dd454ca341f3bcdc4cee913
Content-Disposition: form-data; name="file"; filename="log.log"

sdffsfsfsfsfsfffssfsef

--374728dd2dd454ca341f3bcdc4cee913--

files参用的是multipart/form-data,看来requests库默认没提供单独的multipart/form-data格式的参数,如果想用multipart/form-data,必须用files,查看files参数相关源码

#...site-packages/requests/models.py
class RequestEncodingMixin(object):
......
	def _encode_files(files, data):
		.......
		for (k, v) in files:
	            # support for explicit filename
	            ft = None
	            fh = None
	            if isinstance(v, (tuple, list)):
	                if len(v) == 2:
	                    fn, fp = v
	                elif len(v) == 3:
	                    fn, fp, ft = v
	                else:
	                    fn, fp, ft, fh = v
	            else:
	                fn = guess_filename(v) or k
	                fp = v

	            if isinstance(fp, (str, bytes, bytearray)):
	                fdata = fp
	            elif hasattr(fp, 'read'):
	                fdata = fp.read()
	            elif fp is None:
	                continue
	            else:
	                fdata = fp
	
	            rf = RequestField(name=k, data=fdata, filename=fn, headers=fh)
	            rf.make_multipart(content_type=ft)
	            new_fields.append(rf)
	        body, content_type = encode_multipart_formdata(new_fields)
	        return body, content_type

files是一个字典,每个k的v是一个tuple/list或者直接是fileobject,如果是tuple/list的话,依次表示(data,filename,content_type,headers),传2,3,4个参都行,我们组建form-data也就是组建这个列表

#这里要注意,data必须为None,否则body中会出现filename字段,server端(Flask举例)在读取的时候form表单里就取不到,在files里了
>>>post(url, files={'file':(None, 'sss'), 'test1': (None,'1')})

POST /data/test HTTP/1.1
Host: www.test.com
User-Agent: python-requests/2.23.0
Accept-Encoding: gzip, deflate
Accept: */*
Content-Length: 213
Content-Type: multipart/form-data; boundary=b804251c3152118565134bb8caa0b643
Connection: keep-alive

--b804251c3152118565134bb8caa0b643
Content-Disposition: form-data; name="file"

sss
--b804251c3152118565134bb8caa0b643
Content-Disposition: form-data; name="test1"

1
--b804251c3152118565134bb8caa0b643--

至此,完成requests库用files字段发送form-data格式数据

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值