最近在寫腳本時有一個功能是上傳附件,也趁這個機會學習了下對於上傳文件類的接口該如何進行傳參
本次介紹2種方式來上傳附件:一種是通過jmeter;另一種是通過python的requests庫
接口參數分析
在講具體方法之前,先來分析下這次上傳附件接口的headers與攜帶的參數信息
headers種主要看content-type,這個請求中的content-type如下
content-type: multipart/form-data; boundary=----WebKitFormBoundaryKtD3qxHwCR9S9Wdy |
------WebKitFormBoundaryKtD3qxHwCR9S9Wdy
Content-Disposition: form-data; name="type"
3
------WebKitFormBoundaryKtD3qxHwCR9S9Wdy
Content-Disposition: form-data; name="file"; filename="test.jpg"
Content-Type: image/jpeg
------WebKitFormBoundaryKtD3qxHwCR9S9Wdy--
|
可以看到消息主體里按照字段個數又分為多個結構類似的部分,每部分都是以 --boundary
開始,緊接着是內容描述信息,然后是回車,最后是字段具體內容(文本或二進制);
如果傳輸的是文件,還要包含文件名和文件類型信息;
消息主體最后以 --boundary--
標示結束;
另外boundary每次都是隨機生成的!!!
更多內容請看:https://imququ.com/post/four-ways-to-post-data-in-http.html
1. jmeter上傳附件
以我這個請求為例,來說明一下如何填寫請求參數,先把請求body再次放在在這里
------WebKitFormBoundaryKtD3qxHwCR9S9Wdy
Content-Disposition: form-data; name="type"
3
------WebKitFormBoundaryKtD3qxHwCR9S9Wdy
Content-Disposition: form-data; name="file"; filename="test.jpg"
Content-Type: image/jpeg
------WebKitFormBoundaryKtD3qxHwCR9S9Wdy--
|
如果請求body中除了需要上傳文件外,還需要上傳其他參數,如上面的第一部分,表示有個參數名為"type",它的值為3,需要把它填入jmeter的【參數】中
在【文件上傳】中填寫附件的參數信息
(1) 勾選【對POST使用multipart/form-data】
(2) 文件名稱:附件絕對路徑
(3) 參數名稱:這個根據你在chrome控制台看到參數名稱來填寫,回頭看上面貼出來的請求body
第二部分就是對上傳文件的文件名和文件類型的描述,觀察內容可以發現
name=“file”,所以這里的參數名稱就填寫“file”(填錯的話,一般會報錯的)
Content-Type為image/jpeg,所以jmeter中的MIME類型就填寫“image/jpeg”
ps.關於headers的一點說明:剛開始的時候,我一直想着在信息頭管理器中加上固定的 content-type: multipart/form-data; boundary=----WebKitFormBoundaryKtD3qxHwCR9S9Wdy
但是實際運行腳本時總是報錯,查看結果樹中的請求頭,也並不是自己定義的這個boundary,貌似自己生成了一個boundary
后來把請求頭中的content-type去掉后,再次運行就成功了
綜上,在jmeter中進行文件上傳的請求腳本就寫好了
2. 使用python的requests庫上傳文件
在使用requests上傳文件時,可以先看看官方文檔的一段描述:
https://requests.readthedocs.io/zh_CN/latest/user/quickstart.html#post-multipart-encoded
Requests 使得上傳多部分編碼文件變得很簡單:
>>> url = 'http://httpbin.org/post' >>> files = {'file': open('report.xls', 'rb')} >>> r = requests.post(url, files=files) >>> r.text { ... "files": { "file": "<censored...binary...data>" }, ... }
你可以顯式地設置文件名,文件類型和請求頭:
>>> url = 'http://httpbin.org/post' >>> files = {'file': ('report.xls', open('report.xls', 'rb'), 'application/vnd.ms-excel', {'Expires': '0'})} >>> r = requests.post(url, files=files) >>> r.text { ... "files": { "file": "<censored...binary...data>" }, ... }
通過這個例子,可以知道requests上傳文件是通過files關鍵字來完成的:先定義一個變量files,它是一個字典,key=file,value則是打開的二進制文件;然后發送post請求時,帶上file參數即可
拿我這次的請求來說,如下
files = {"file": ("/data/image/test.jpg", 'rb'))} payload={
type: 3 } response = requests.post(url, files=files, data=payload, headers=headers)
payload中定義的是請求body中的type參數;files是本次要上傳的文件;
發送post請求時,需要用files關鍵字發送文件,用data關鍵字發送payload
執行這段腳本能夠得到和jmeter同樣的結果
接下來查看下發送出的請求攜帶的請求頭是什么樣的
print(response.request.headers)
結果如下
{ 'User-Agent': 'python-requests/2.22.0', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive','Content-Length': '110824', 'token': 'sImDk2YzBkOTkzNFwiLFwiZW1haWxcIjpcIjgxZjcwZjJkOWFmODA1MD', 'Content-Type': 'multipart/form-data; boundary=59a681a11824f2dd578becdd4195cf9b' }
可以發現,python自己給它補全了Content-Type,並且boundary也是自己生成的一段字符
至於如何自己定義boundary還得再研究研究