1. 程式人生 > >看完這篇部落格,我保證你肯定會做介面測試了。

看完這篇部落格,我保證你肯定會做介面測試了。

最近給公司的新員工培訓web api介面測試,發現這一塊的內部需求還比較大,不僅僅是新員工,包括一些經常寫介面測試老員工,對介面也是似懂非懂的,所以我絕對有必要寫一篇部落格來普及下。

在我們公司內部,一般使用ruby或者python語言來做介面測試,這篇檔案主要是講解使用python語言來做介面測試。

如果要做介面測試,其實只要會抓包,會組裝http請求頭和請求體,會檢查http響應頭和響應體,就可以可以,所以我們需要需要掌握下面這些知識!!!另外還需要掌握一些常用的測試框架,比如unittest和pytest等

1、python語言requests庫

2、http協議基本知識,包括請求頭,響應頭、請求體、響應體

3、session-cookie(如果大家對session和cookies不熟悉,可以看我之前寫 的部落格)

https://www.cnblogs.com/bainianminguo/p/9147418.html

https://www.cnblogs.com/bainianminguo/p/8850043.html

4、fiddler抓包工具

5、測試框架,這裡不會講,大家有興趣可以看下我之前寫的部落格,介紹unittest測試框架

https://www.cnblogs.com/bainianminguo/p/11706244.html

https://www.cnblogs.com/bainianminguo/p/11616526.html

 

下面進入正題,聽我娓娓道來。

一、http協議

1、簡介

web api介面大都是基於http協議的,所以要進行介面測試,首先要了解HTTP協議的基礎知識。

HTTP協議全稱是超文字傳輸協議。由於HTTP最初是用來在瀏覽器和網站伺服器之間傳輸超文字的(網頁,視訊,圖片等)資訊的。由於HTTP簡潔易用,後來,不僅僅是瀏覽器和伺服器之間使用它,伺服器和伺服器之間,手機app和伺服器之間,都廣泛的採用,成了一個軟體系統間通訊的首選協議之一。

HTTP協議有好幾個版本,包括0.9、1.0、1.1、1.2,當前最廣泛使用的是HTTP/1.1版本

HTTP協議最大的特點是通訊雙方分為客戶端和服務端。

由於目前HTTP是基於TCP協議,所以要進行通訊,客戶端必須先河服務端建立TCP連線。而且HTTP雙方的資訊互動,必須要這樣一種形式

a、客戶端先發送http請求(request)給伺服器

b、然後伺服器傳送http響應(response)給客戶端

c、特別要注意,在http協議中,服務端是不能主動發訊息給客戶端的

流程圖如下

 

 

 

http1.1版本先建立TCP連線,然後在這個連線內可以進行多次互動資訊,這裡注意,是客戶端主動給服務端發請求的

 

二、http請求

下面是http的get請求和http的post請求的示例

GET /mgr/login HTTP/1.1
Host: 192.168.3.1
User-Agent:Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36
Accept-Language:zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4
Accept-Encoding:gzip, deflate, sdch

  

POST /api/test HTTP/1.1
Host:192.168.3.1
Origin:http://192.168.3.1
Referer:http://192.168.3.1/html/index.html
User-Agent:Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36
Content-Type:application/json;charset=UTF-8
Content-Length:214
Accept-Language:zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4
Accept-Encoding:gzip, deflate

{"csrf":{"csrf_param":"35iUJau6mdmmJeIg0N8W80OmoMK8A2Kr","csrf_token":"KfKSfpH0hnsSc0uQyX6ZUB8i8KRFSZ0C"},"data":{"username":"admin","firstnonce":"c7eb46830667147fc62838e7ba9a0c09187d28bafa45b133897efa9d4e46a880"}}

  

一個http請求訊息由下面幾個部分組成

a、請求行 request line

是http的第一行的內容。表示要操作什麼資源,使用的http協議的版本是什麼,裡面包含了三部分訊息。請求的方法、操作資源的地址、協議的版本號

 

GET https://securepubads.g.doubleclick.net/pagead/adview?ai=C3a-FX0L-XZ7nH8Hn2gT1vpKQBofP2MxZl96OgJYKsfz66E0QASC3tpYCYJ0ByAEBqQIDDuevOSiDPuACAKgDAcgDCqoE5AFP0PxttPf1dpFDQI04YpU7K4Qhq0WGx-H6233i9kddKMRmZ8rfGeWBQrr479rzo9D8pahF4GnAvGpwUHZntCL7HcXpQi_xqWQt3alVu7iKmqOQ2r6wzaMJli0vfW_rWq9l6hMmC3THotaE3aaCu8-yQ18_cRaCfgKTCRRx0Eze2gWYfJic33lRDI5NHSVfSlXDsc3SItNtoxG4tZhzRdw3omfX6oWwyvxUVboGzJwd8Rfij2Abfe4gFMviIlfhgVkNNRVv3U-Zhi6Xu5dTGhbV952-dpPUto1PgnRuTQpfsnvJ9UbABKmyupce4AQBkgUECAQYAZIFBAgFGASAB9GIrh6oB47OG6gH1ckbqAeT2BuoB7oGqAfy2RuoB6a-G6gH7NUb2AcB8gcEEPCNAtIIBwiAYRABGB2ACgHICwHYEwKIFAE&sigh=RmPL7gCMtsg&tpd=AGWhJmu9ZlDGyMSGWoSTQKbLoOl12TOWdSdugT6uZH2DizpViw HTTP/1.1

  

b、請求方法

Get請求

從伺服器上獲取資源資訊,這是一種最常見的請求

比如要從伺服器獲取網頁資源,獲取圖片資源,獲取使用者資訊資料等

 

Post請求

新增資源資訊到伺服器進行處理,例如要新增使用者資訊,上傳圖片資料到伺服器等,具體的資料資訊,通常在HTTP請求的訊息體中,這個後面會講

 

 Put請求

請求伺服器更新資源資訊

比如要更新使用者、姓名地址等等

具體的更新的資料資訊,通常在HTTP的訊息體中,後面會講

 

Delete請求

請求伺服器刪除資源資訊

比如要刪除某個使用者,某個資源等等

HTT片協議還有許多其他的方法,比如PATCH,HEAD等,不是特別常用,暫且不講

 

c、資源地址

 

 

 

d、請求頭

 

 

 

這裡業務大家有個疑問,我的http請求是建立在tcp連線的基礎上的,為什麼這裡還要傳遞一個host呢?因為我們知道ip地址了,但是這個ip地址上可能有多個網站,所以這裡要指定我們要訪問的具體是哪個網站

請求體的http請求下面的內容,裡面存放一些資訊。

比如請求傳送的服務端的域名是什麼,希望接受的響應訊息使用語言,請求訊息體的長度等等;

通常請求頭有好多個,一個請求頭佔據一行

單個請求頭的格式是:名字:值

 

e、請求體

請求的url,請求頭中可存放一些資料資訊,但是有些資料資訊,往往需求存放在訊息體中國;特別是post,put的請求,新增,修改的資料資訊通常都是存放在請求訊息體中的;

如果HTTP請求有訊息體,協議規定,需要在訊息頭和訊息體之間插入一個空行,隔開他們;

請求訊息體中儲存了要提交個服務端的資料資訊

比如:客戶端要上傳一個檔案給伺服器,就可以通過http請求傳送檔案資料給服務端;

檔案的資料就應該在請求的訊息體中

請求的訊息體通常是某種格式的字串,常見的有三種,但是最常用的還是json格式

Json

Xml

www-form-urlencoded

後面會有詳細的描述

 

request payload就是一個請求體,下面這個格式就是Json格式的訊息體

 

 

 

請求體中不僅僅可以存放字串,還可以放二進位制資訊,比如以下視訊、文字之類的,用於我們上傳檔案的場景,不過通常介面測試不會涉及二進位制資訊,都是字串資訊,後面我會專門寫一篇部落格來介紹如何上傳檔案

 

2、http響應

響應的訊息我們重點關注狀態碼

a、2xx

通常表示請求訊息沒有問題,而且伺服器也正確處理了

b、3xx

這是重定向響應,常見的是是301、302,表示客戶端的這個請求的url地址已經改變了,需要客戶端重啟發起一個請求到另外一個url

c、400

表示客戶端請求不符合介面要求,比如格式完全錯誤

d、401

表示客戶端需要先認證才能傳送請求

e、403

表示客戶端美譽哦許可權要求伺服器處理這樣的請求,比如普通使用者的沒有管理員的許可權

f、404

表示客戶端方法的url不存在

g、5xx

表示服務端在處理請求中,傳送了未知錯誤,通常是服務端的程式碼設計的問題,或者服務端系統出了故障了

 

有了以上的基礎,我們就可以做web的介面測試了

二、介面測試

1、什麼是介面測試

我們通常說的介面測試,其實就是對軟體系統的訊息互動介面的引數,訊息互動介面是軟體系統和其他軟體系統互動的那部分,比如,你正在用瀏覽器使用一個網站,瀏覽器和後端伺服器之間就是訊息互動的;在比如,你手機上使用美團訂餐,美團app和美團服務器之間,也是訊息互動的,當你提交訂單,使用功能微信支付的時候,美團服務器和微信伺服器之間也是通過訊息互動的

 

 

 

 

介面測試就是

依據介面規範,寫出測試用例

使用軟體工具,直接通過訊息介面對被測系統進行訊息收發

驗證被測系統行為是否正確

 

目前軟體系統之間的訊息介面大部分是基於HTTP協議收發的

HTTP協議的特點是,客戶端發出一個HTTP請求給服務端,服務端就返回一個HTTP相應,好像API程式呼叫;

所有介面測試通常又被稱為API介面測試或者WEB API介面測試

 

API介面傳遞資料資訊是通過HTTP協議進行收發的,網站獲取網頁,圖片,css等資源,也是通過HTTP協議進行收發的

那麼這兩者有什麼區別呢?為什麼獲取網頁,圖片這些HTTP訊息不叫做API介面訊息呢?

網頁,圖片,css這些資源都是靜態資源,就是一個一個檔案儲存在伺服器中,獲取這些訊息,服務端直接讀取檔案,返回給客戶端即可,無需特別的資料處理

 

而API介面請求訊息,通常都需要服務端程式進行一番處理,比如對請求的許可權檢查,從資料庫中讀出資料,進行訊息過濾和格式轉換,最後在HTTP響應中返回給客戶端

介面測試需要工具和被測系統之間進行訊息的收發,這個工具可以是別人開發的,也可以自己開發,基於HTTP的介面測試工具有Postman,Jmeter等

 

2、fiddler工具

這裡我們使用python語言中的requests庫和fiddler抓包工具

Fiddler:代理式抓包

大家一定會反問,我的瀏覽器就是可以抓包了,為什麼還要安裝fiddler,多此一舉?

其實不然,因為我們是用python的requests庫去做介面測試,瀏覽器是抓不到我們發的請求的,所以需要安裝fiddler來抓包,確保我們傳送的http請求是正確的

 

fiddler啟動後,會啟動一個代理伺服器,監聽在8888埠上,http客戶端需要設定fiddler作為代理,把http請求訊息傳送給fiddler,fiddler轉發http訊息給服務端,服務端返回訊息也是先返回給fiddler。再由fidddler轉發給客戶端

如下圖所示

 

 

  

fiddler安裝後,會預設配置作業系統級別的代理,可以通過下面的方式檢視

 

 

 

安裝fiddler需要配置一個過濾項,因為預設fiddler是作為一個系統代理,所以fiddler抓到包會很多,所以需要配置一個過濾項

 

 

 

 

同樣,這裡的配置是支援萬用字元的

 

 

 

抓包

 

 

 

 

檢視原始的請求訊息

 

 

 

 

我們可以在python程式碼裡配置代理,然後通過fiddler抓包來判斷我們發的包是否準確,這裡需要配置http和https協議的代理

import requests

proxies = {
    "http":"127.0.0.1:8888",
    "http1": "127.0.0.1:8888"
}

res = requests.get(
    url = "htt://www.baidu.com",
    proxies = proxies
)

  

我們可以通過fiddler進行抓包

 

 

 

fiddler如果 要配置手機抓包代理,需要保證安裝fiddler和手機在同一個區域網中

 

 

 

在手機的無線網路處配置代理,代理指向執行fiddler的電腦的ip即可,埠是8888

 

3、requests庫的請求

a、構建請求的url引數,這個一般在get請求使用較多

什麼是url引數

比如

https://www.baidu.com/s?wd=iphone&res_spt=1

  

問號後面的部分wd=iphone&res_spt=1就是url引數,每個引數之間就用&隔開的。

上面的例子中有兩個引數wd和res_spt,他們的值分別iphone和1

url引數引數的格式,有個術語叫urlencoded格式

 

使用requests傳送HTTP請求,url裡面的引數,通常可以直接在url裡面,比如

 

 

但是有的時候,我們的url中引數裡面有特殊字元,比如引數中的值包含了一個&這個符號或者引數很多的話,我們可以採用下面的方法,構建一個字典,然後把這個字典傳遞給params引數 

也可以用下面的方式傳遞url引數

res = requests.get(
    url = "http://www.baidu.com/",
    params = {
        "wd":"iphone",
        "res_spt":"1"
    },
    proxies = proxies
)

  

b、構建請求訊息頭

有的時候,我們需要自定義一些http的訊息頭

每個訊息頭也就是一種鍵值對的格式存放資料,在requests,只需要把抓包中的請求頭資訊放在一個字典中,然後傳遞headers即可

res = requests.get(
    url = "http://www.baidu.com/",
    headers = {
        "Host": "192.168.3.1",
        "User-Agent":"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
        "Accept-Language":"zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4",
        "Accept-Encoding":"gzip, deflate, sdch"
        },
    params = {
        "wd":"iphone",
        "res_spt":"1"
    },
    proxies = proxies
)

  

 

c、構建請求的訊息體

當我們進行api介面測試的時候,根據介面規範,構建的http請求,通常需要構建訊息體

http的訊息體就是一串位元組,裡面包含了一些資訊,這些資訊可能是文字,比如html網頁作為訊息體,也可能是視訊,音訊資訊

訊息體可能很短,只有一個位元組,比如字元a,也可能很長,有幾百個位元組

最常見的訊息體格式當然是表示網頁內容的html

當時在web api介面測試中,常見的HTTP訊息體的格式有三種,urlencoded,json,xml

注意:訊息體採用什麼格式,是由開發人員設計決定的,開發人員也可以自定義格式,但是我們通常不會自定義的

 

xml格式

前面時候了,訊息體就是存放資訊的地方,資訊的格式完全取決於設計者的需求,如果設計者決定使用xml格式傳輸一段資訊,用requests庫,只需要這樣就可以了

 

playload = """
    <?xml version="1.0"?>
    <methodCall>
        <methodName>examples.getStateName</methodName>
        <params>
            <param>
                <value><i4>41</i4></value>
            </param>
        </params>
    </methodCall>"""

res2 = requests.post(
    url = "http://www.baidu.com/",
    headers = {
        "Host": "192.168.3.1",
        "User-Agent":"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
        "Accept-Language":"zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4",
        "Accept-Encoding":"gzip, deflate, sdch",
        "Content-Type": "text/xml"
        },
    data=playload.encode("utf-8"),
    proxies = proxies
)

  

由於訊息體都是位元組串,我們直接把字串使用utf-8解碼,然後傳遞給data引數即可,這裡需要注意,需要設定Content-type=text/xml

 

 

 

 

使用data引數,儲存訊息體的資料,如果傳遞的是一個字串,在http請求中,需要編碼為位元組碼,預設的編碼格式latin-1,這種編碼格式是不支援中文的;通常我們使用utf-8的編碼格式

通過fiddler抓包

 

 

 

檢視請求的原始資訊

 

 

 

 

 

 

Urlencoded格式

這種格式的訊息體就是一個key-value鍵值對的格式存放資料,如下所示

key1=value1&key2=value2

 

Requests傳送這樣的資料,當然可以直接把這種格式的字串傳入到data引數裡;但是這樣寫的話,如果引數本身就有特殊字元,比如等號,就會有歧義

我們還有更方便的方法,只需要將這些鍵值對的資料構建一個字典,如下

playload = {
    "key1":"value1",
    "key2":"value2"
}

res2 = requests.post(
    url = "http://www.example.com",
    headers = {
        "User-Agent":"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
        "Accept-Language":"zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4",
        "Accept-Encoding":"gzip, deflate, sdch",
        "Content-Type": "application/x-www-form-urlencoded;charset=utf-8"
        },
    data=playload,
    proxies = proxies
)

  

這裡需要注意下面2個地方

 

 

 

 

通過fiddler抓包

先看請求頭

 

 

 

這裡明顯可以看到,請求頭和請求體中間有一個空行

 

 

 

看下請求體中的資料

 

 

 

 

Json格式的訊息體

Json字串一律用雙引號,不能用單引號

Json字串最後一個元素的後面不能加逗號

 

其實我們要把資料放到訊息體中,最終的資料都是位元組串,也就是把str.encode()

json格式當前被web api介面廣泛採用

json是一種表示資料的語法格式,他和python表示資料的語法非常像

json格式有兩種方式構建訊息體

方式1

playload = {"title": "test", "sub": [1, 2, 3]}
res2 = requests.post(
    url = "http://www.example.com",
    headers = {
        "User-Agent":"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
        "Accept-Language":"zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4",
        "Accept-Encoding":"gzip, deflate, sdch",
        "Content-Type": "application/json;charset=utf-8"
        },
    json=playload,
    proxies = proxies
)

  

注意下面這裡

 

 

 

方式2

import json
playload = {"title": "test", "sub": [1, 2, 3]}
res3 = requests.post(
    url = "http://www.example.com",
    headers = {
        "User-Agent":"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
        "Accept-Language":"zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4",
        "Accept-Encoding":"gzip, deflate, sdch",
        "Content-Type": "application/json;charset=utf-8"
        },
    data = json.dumps(playload,ensure_ascii=False).encode("utf-8"),
    proxies = proxies
)

  

注意下面這裡

 

 

4、requests庫的響應

a、檢查HTTP響應狀態碼

要檢查HTTP響應的狀態碼,直接通過response物件的status_code屬性獲取

import json
playload = {"title": "test", "sub": [1, 2, 3]}
res3 = requests.post(
    url = "http://www.example.com",
    headers = {
        "User-Agent":"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
        "Accept-Language":"zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4",
        "Accept-Encoding":"gzip, deflate, sdch",
        "Content-Type": "application/json;charset=utf-8"
        },
    data = json.dumps(playload,ensure_ascii=False).encode("utf-8"),
    proxies = proxies
)


print(res3.status_code)

  

執行結果發現返回的結果狀態碼就是200

 

 

 

 

如果故意寫一個不存在的地址

import requests

proxies = {
    "http":"127.0.0.1:8888",
    "http1": "127.0.0.1:8888"
}

res = requests.get(
    url = "http://192.168.3.1/html/index4.html",
    proxies = proxies
)

print(res.status_code)

  

執行結果發現返回的狀態碼就是404

 

 

 

 

b、檢查響應的訊息頭

要檢查HTTP響應的訊息頭,直接通過response物件的header屬性獲取

import json
import requests
import pprint
playload = {"title": "test", "sub": [1, 2, 3]}
proxies = {
    "http":"127.0.0.1:8888",
    "http1": "127.0.0.1:8888"
}
res3 = requests.post(
    url = "http://www.example.com",
    headers = {
        "User-Agent":"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
        "Accept-Language":"zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4",
        "Accept-Encoding":"gzip, deflate, sdch",
        "Content-Type": "application/json;charset=utf-8"
        },
    data = json.dumps(playload,ensure_ascii=False).encode("utf-8"),
    proxies = proxies
)


print(pprint.pprint(dict(res3.headers)))

  

結果如下

 

 

 

 

 

 

 

c、檢查響應訊息體的文字內容

前面我們已經說過,要獲取響應的訊息體的文字內容,直接通過response物件的text屬性即可獲取

import requests
import pprint
#
proxies = {
    "http":"127.0.0.1:8888",
    "http1": "127.0.0.1:8888"
}
#
res = requests.get(
    url = "http://mirrors.sohu.com",
    proxies = proxies
)
#
#
# print(res.text)
print(pprint.pprint(dict(res.headers)))
print(res.encoding)

  

  

響應體其實也是位元組串,但是我們呼叫text方法沒有設定解碼格式,他是怎麼解碼?他是根據響應頭的contend-type來決定解碼格式,有的時候會指定,但是大部分不會指定

我們

 

 

 

 

我們可以看到我們列印的解碼格式,和content-Type中是一樣的

 

 

 

 

如果有的時候中文解碼出來是亂碼,我們可以手動指定解碼格式

 

 

 

 

 

如果我們想列印響應體的位元組串可以使用content方法

 

 

 

 

 

5、session

a、原理

我們來思考一個問題,一個網站,比如一個購物網站,服務成千上萬的的客戶,那麼多客戶同時訪問網站,挑選物品,購物估算,都是通過hTTP請求來訪問網站的,這個網站的服務端怎麼區分每個HTTP請求呢?網站的服務端是怎麼實現的?

一種最常見的方式就是:通過Session+cookies機制

session翻譯成中文就是會話的意思

session大體的原理如下面2個圖

 

 

 

 

 

 

 

 

 

http協議規定了,網站的服務端放HTTP響應的訊息頭set-Cookies裡面的資料,叫做cookies資料,瀏覽器客戶端必須要儲存下來。而且後續訪問該網站,必須在http的請求頭Cookies中攜帶儲存的所有的cookie資料

使用者使用客戶端登陸服務端,服務端進行驗證,比如驗證使用者名稱和密碼,驗證通過後,服務端系統高就會為這次登陸建立一個seesion,同時建立一個唯一的sessionID。標誌這個session。然後,服務端通過HTTP響應,把sessionID告訴客戶端,客戶端在後面的HTTP請求的訊息頭,都要包含這個sessionID。這樣服務端就會知道,這個供求對應哪個session,從而知道這次的請求對應哪個使用者;

 

 

 

 

從上圖可以看出,服務端是通過HTTP的響應頭set-cookies把產生的sessionID告訴客戶端。

 

 

 

 

客戶端的後續請求,是通過HTTP請求的請求頭Cookies告訴服務端他所持有的sessionid的

 

b、request庫支援session的

request處理session-cookies

我們在python程式碼中如果接收到伺服器的http響應,其他set-cookies的資料怎麼儲存呢?後續怎麼樣把請求訊息頭中cookies中呢?

前面學過HTTP響應中如何獲取響應頭,構建請求怎麼設定請求頭,完全可以處理。

但是requests庫為我們這個處理

requests庫給我們提供了一個session類。通過這個類,無需我們操心cookies和session這個事情。reqeusts庫會自動幫我們儲存服務端發揮的cookies資料,HTTP請求自動在訊息頭中放入cookies資料

如下所示

import requests
import json
session = requests.session()

playload = {"title": "test", "sub": [1, 2, 3]}
proxies = {
    "http":"127.0.0.1:8888",
    "http1": "127.0.0.1:8888"
}

res = session.post(
    url = "http://www.example.com",
    headers = {
        "User-Agent":"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
        "Accept-Language":"zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4",
        "Accept-Encoding":"gzip, deflate, sdch",
        "Content-Type": "application/json;charset=utf-8"
        },
    data = json.dumps(playload,ensure_ascii=False).encode("utf-8"),
    proxies = proxies
)



res = session.get()

  

&n