Sanic request 請求資料

veelion發表於2019-03-21

在《Sanic框架介紹》一節中的簡單示例中,路由函式test()有一個引數request,它是一個Request物件,包含了客戶端(瀏覽器)發過來的HTTP請求的各類資料。

sanic 請求資料

Sanic Request物件的屬性

(1)json :JSON格式資料
當客戶端POST來的資料是json格式時,可以通過request.json來訪問:

from sanic import response

@app.route('/json', methods=['POST'])
async def post_json(request):
    return response.json({"received": request.json})

(2)args (字典):查詢字串變數

查詢字串變數就是說URL中問號?及其後面的部分,比如,?name=jim&age=12。這樣帶查詢變數的URL被解析後,args字典就是這樣的:{'name':['jim'], 'age': ['12']}。request物件的屬性query_string就是未解析的字串值:name=jim&age=12。該屬性提供了預設的解析查詢變數的策略,稍微我們介紹如何改變解析策略。

from sanic import response

@app.route('/args')
async def args(request):
    return response.json({
        "parsed": True,
        "args": request.args,
        "url": request.url,
        "query_string": request.query_string,
    })


(3)query_args(列表)
該屬性提供了另外一種url引數的形式,它是元組(key, value)的列表。該屬性提供了預設的解析查詢變數的策略,稍微我們介紹如何改變解析策略。

對於前面的URL查詢變數?name=jim&age=12,對應的query_args列表就是:
[('name', 'jim'), ('age', '12')]

如果同一個key對應多個value的情況?name=jim&age=12&name=tom,對應的query_args就是:
[('name', 'jim'), ('age', '12'), ('name', 'tom')]

Sanic 18.12 版本已經沒有 query_args 這個屬性

下面看具體程式碼來理解args等查詢變數:

from sanic import Sanic
from sanic.response import json

app = Sanic()

@app.route('/args')
async def test(request):
    return json({
        "parsed": True,
        "url": request.url,
        "query_string": request.query_string,
        "args": request.args,
        "raw_args": request.raw_args,
        # "query_args": request.query_args,
    })


if __name__ == '__main__':
    app.run(host='127.0.0.1', port=8888)

訪問這個web應用的輸出是:

{
  "parsed": true,
  "url": "http://127.0.0.1:8888/args?name=jim&age=12&name=tom",
  "query_string": "name=jim&age=12&name=tom",
  "args": {
    "name": [
      "jim",
      "tom"
    ],
    "age": [
      "12"
    ]
  },
  "raw_args": {
    "name": "jim",
    "age": "12"
  }
}

注意 raw_args字典的value不是列表,而是args字典中value的第一個值。這個屬性將來會被棄用。

(4)files(字典):擁有name、body和type的檔案物件的字典
客戶端(瀏覽器)上傳的檔案包含在Form data中,files字典的key是Form物件中檔案物件的名稱(不是檔名),這個檔案物件有name(檔名)、body(檔案資料)和type(檔案型別)三個屬性。

from sanic import Sanic
from sanic import response

app = Sanic()

@app.route('/')
async def index(request):
    html = ('<html><body>'
            '<form action="/files" method="post" enctype="multipart/form-data">'
            '<input type="file" name="file1" /> <br />'
            '<input type="file" name="file2" /> <br />'
            '<input type="submit" value="Upload" />'
            '</form>'
            '</body></html>')
    return response.html(html)


@app.route("/files", methods=['POST'])
async def post_json(request):
    test_file = request.files.get('file1')
    file_parameters = {
        'body': len(test_file.body),
        'name': test_file.name,
        'type': test_file.type,
    }

    return response.json({
        "received": True,
        "file_object_names": request.files.keys(),
        "test_file_parameters": file_parameters
    })


if __name__ == '__main__':
    app.run(host='127.0.0.1', port=8888)

執行上面這個web應用,並用瀏覽器開啟http://127.0.0.1:8888/這個地址,可以看到一個簡單的上傳介面,需要選擇兩個檔案,然後點選“Upload”,就可以看到這個web應用返回的json資料:

// 20190321203852
// http://127.0.0.1:8888/files

{
  "received": true,
  "file_object_names": [
    "file1",
    "file2"
  ],
  "test_file_parameters": {
    "body": 33759,
    "name": "ft-generator.jpg",
    "type": "image/jpeg"
  }
}

注意 從結果可以看出,requests.files.keys()是網頁html中inputname,不是檔名。

(5)form(字典):以POST方式傳遞的form變數
在上面files例子中的網頁html部分加一行:

<input type="text" name="title" /> <br />

post_json()函式的返回json裡面加上request.form,就可以看到request.form的內容了:

{
  "received": true,
  "form": {
    "title": [
      "猿人學Python"
    ]
  },
  "file_object_names": [
    "file1",
    "file2"
  ],
  "test_file_parameters": {
    "body": 33759,
    "name": "ft-generator.jpg",
    "type": "image/jpeg"
  }
}

(6)body(位元組串):POST的原始資料。
這個屬性允許我們得到request的原始資料。

(7)headers(字典):包含請求頭(headers)的不區分大小寫的字典。

(8)method(字串):HTTP請求的方法,比如GET, POST等。

(9)ip(字串):客戶端(瀏覽器)的IP地址。

(10)port(字串):客戶端(瀏覽器)的埠地址。

(11)socket(元組):客戶端(瀏覽器)的(IP, port)

(12)app:正在處理該request的Sanic應用物件的引用。當我們在blueprint檔案裡面或其它模組需要使用全域性的app時可以通過request.app來訪問它。

以下都是字串屬性:

(13)url:請求的完整URL。

(14)scheme:請求的URL scheme:httphttps

(15)host:請求的host:127.0.0.1:8888

(16)path:請求的路徑path: 比如/files

(17)query_string:請求的查詢字串,name=jim&age=12或空字串''

(18)uri_template:路由處理器匹配的模板:/posts/<id>/

(19)token 授權header的值,,比如Basic YWRtaW46YWRtaW4=

Sanic Request使用getgetlist訪問值

request的屬性中是字典的,其實是dict的一個子類RequestParameters。它與內建字典不同的是get()getlist()方法。

  • get(key, default=None)dict的get方法一樣。如果value是list時,只返回list的第一個元素。
  • getlist(key, default=None) 返回整個list。
from sanic.request import RequestParameters

args = RequestParameters()
args['titles'] = ['Post 1', 'Post 2']

args.get('titles') # => 'Post 1'

args.getlist('titles') # => ['Post 1', 'Post 2']

總結

request物件是web應用要處理的物件,它包含了客戶端(瀏覽器)的請求資料,通過它的各種屬性來訪問這些請求資料。

猿人學banner宣傳圖

我的公眾號:猿人學 Python 上會分享更多心得體會,敬請關注。

***版權申明:若沒有特殊說明,文章皆是猿人學 yuanrenxue.com 原創,沒有猿人學授權,請勿以任何形式轉載。***

相關文章