httpc庫基於cf框架都內部實現的socket編寫的http client庫.git
httpc庫內置SSL支持, 在不使用代理的狀況下就能夠請求第三方接口.github
httpc支持header、args、body、timeout請求設置, 完美支持各類httpc調用方式.web
httpc庫使用前須要手動導入httpc庫: local httpc = require "httpc"
.json
調用get方法將會對domain發起一次HTTP GET請求.c#
domain是一個符合URL定義規範的字符串;api
HEADER是一個key-value數組, 通常用於添加自定義頭部;數組
ARGS爲請求參數的key-value數組, 對於GET方法將會自動格式化爲:args[n][1]=args[n][2]&args[n+1][1]=args[n+1][2]
;瀏覽器
TIMEOUT爲httpc請求的最大超時時間;bash
調用post方法將會對domain發起一次HTTP POST請求, 此方法的content-type
會被設置爲:application/x-www-form-urlencoded
.併發
domain是一個符合URL定義規範的字符串;
HEADER是一個key-value數組, 通常用於添加自定義頭部; 不支持Content-Type與Content-Length設置;
BODY是一個key-value數組, 對於POST方法將會自動格式化爲:body[n][1]=body[n][2]&body[n+1][1]=body[n+1][2]
;
TIMEOUT爲httpc請求的最大超時時間;
json方法將會對domain發起一次http POST請求. 此方法的content-type
會被設置爲:application/json
.
HEADER是一個key-value數組, 通常用於添加自定義頭部; 不支持Content-Type與Content-Length設置;
JSON必須是一個字符串類型;
TIMEOUT爲httpc請求的最大超時時間;
file方法將會對domain發起一次http POST請求.
HEADER是一個key-value數組, 通常用於添加自定義頭部; 不支持Content-Type與Content-Length設置;
FILES是一個key-value數組, 每一個item包含: name(名稱), filename(文件名), file(文件內容), type(文件類型)等屬性. 文件類型可選.
TIMEOUT爲httpc請求的最大超時時間;
全部httpc請求接口均會有2個返回值: code
, response
. code爲http協議狀態碼, response爲迴應body(字符串類型).
參數不正確, 鏈接被斷開等其它錯誤, code將會爲nil, response爲錯誤信息.
什麼是一次性httpc請求呢?
每次咱們使用httpc庫在請求第三方http接口的時候, 都會在接口返回後關閉鏈接. 這在平常使用中一邊也沒什麼問題.
可是當咱們須要屢次請求同一個接口的時候, 每次請求完畢就關閉鏈接顯然不是那麼高效, 如今咱們嘗試使用一個http class對象來解決這個問題.
注意: httpc class對象不能對不一樣域名的接口使用同一個鏈接, 這會返回一個錯誤調用給使用者.
要使用httpc的class
須要導入httpc的class庫, 導入方式爲: local httpc = require "httpc.class"
.
當須要使用httpc發起請求以前, 須要先建立一個httpc的對象, 如: local hc = httpc:new {}
. httpc對象建立與初始化完畢後, 使用方式同上述API所示.
hc
與httpc
擁有相同的API, 可是須要使用不一樣的調用方式. 如: hc:get
、hc:post
、hc:json
、hc:file
.
一旦hc
使用完畢時, 須要顯示的調用hc:close()
方法來關閉建立的httpc對象並銷燬httpc的鏈接.
如今, 讓咱們將上面學到的API使用方式運用到實踐中.
在main.lua
中啓動一個httpd
的server.
local httpd = require "httpd" local json = require "json" local app = httpd:new("httpd") app:listen("", 8080) app:run()
咱們先利用httpd
庫啓動一個server服務, 而且對外提供IP歸屬地查詢接口
app:api('/ip', function(content) local httpc = require "httpc" local args = content.args if not args or not args['ip'] then return json.encode({ code = 400, msg = "錯誤的接口調用方式", data = json.null, }) end local code, response = httpc.get("http://freeapi.ipip.net/"..args["ip"]) if code ~= 200 then return json.encode({ code = 401, msg = "獲取數據失敗", data = json.null, }) end return response end)
如今代碼已經完成! 讓咱們打開瀏覽器輸入:http://localhost:8090/ip?ip=8.8.8.8
查看返回數據.
一個請求對應一次回是HTTP協議的本質! 可是咱們常常會遇到批量請求的業務場景, 咱們就以此來設計一個批量請求/返回的例子.
讓咱們假設客戶端將會發送一次POST請求, body爲json類型而且裏面包含一個IP數組: ip_list = {1.1.1.1, 8.8.8.8, 114.114.114.114}.
服務端在接受到這個數組以後, 須要將這ip的歸屬地信息一次性返回給客戶端.
app:api('/ips', function(content) local httpc = require "httpc.class" if not content.json then return json.encode({ code = 400, msg = "錯誤的調用參數", data = json.null, }) end local args = json.decode(content.body) if type(args) ~= 'table' or type(args['ip_list']) ~= 'table' then return json.encode({ code = 400, msg = "錯誤的參數類型", data = json.null, }) end local hc = httpc:new {} local ret = { code = 200 , data = {}} for _, ip in ipairs(args['ip_list']) do local code, response = hc:get("http://freeapi.ipip.net/"..ip) ret['data'][#ret['data']+1] = json.decode(response) end hc:close() return json.encode(ret) end)
因爲普通瀏覽器POST沒法發送json, 讓咱們使用curl
命令行工具進行測試:
curl -H "Content-Type: application/json" -X POST -d '{"ip_list":["1.1.1.1","8.8.8.8","114.114.114.114"]}' http://localhost:8090/ip
返回數據以下:
{"code":200,"data":[["CLOUDFLARE.COM","CLOUDFLARE.COM","","",""],["GOOGLE.COM","GOOGLE.COM","","","level3.com"],["114DNS.COM","114DNS.COM","","",""]]}
上述例子彷佛已經很是完美! 咱們利用鏈接保持的方式進行了3次請求, 這樣已經縮短了請求50%的鏈接消耗(TCP握手).
可是對於很是須要性能的咱們來講: 每次請求須要等到上一個請求處理完畢後才能繼續發起新的請求, 這樣的方式顯然還不足以知足咱們.
這樣的狀況下, httpc
庫提供了一個叫multi_request
的方法. 具體使用方法在這裏.
這個方法可讓咱們同時發送幾十上百個請求來解決單個鏈接阻塞的問題.
如今, 讓我使用httpc
庫的multi_request
方法來併發請求多個接口, 減小鏈接阻塞帶來的問題.
app:api('/ips_multi', function (content) local httpc = require "httpc" if not content.json then return json.encode({ code = 400, msg = "錯誤的調用參數", data = json.null, }) end local args = json.decode(content.body) if type(args) ~= 'table' or type(args['ip_list']) ~= 'table' then return json.encode({ code = 400, msg = "錯誤的參數類型", data = json.null, }) end local requests = {} local responses = { code = 200, data = {}} for _, ip in ipairs(args["ip_list"]) do requests[#requests+1] = { domain = "http://freeapi.ipip.net/"..ip, method = "get", } end local ok, ret = httpc.multi_request(requests) for _, res in ipairs(ret) do responses['data'][#responses['data'] + 1] = res end return json.encode(responses) end)
好的, 如今讓咱們再次使用curl
工具進行測試:
curl -H "Content-Type: application/json" -X POST -d '{"ip_list":["1.1.1.1","8.8.8.8","114.114.114.114"]}' http://localhost:8090/ips_multi
咱們能夠從cf的請求迴應時間看到, 響應時間消耗再次下降了50%.
[candy@MacBookPro:~/Documents/core_framework] $ ./cfadmin [2019/06/16 17:45:21] [INFO] httpd正在監聽: 0.0.0.0:8090 [2019/06/16 17:45:21] [INFO] httpd正在運行Web Server服務... [2019/06/16 17:45:23] - ::1 - ::1 - /ips_multi - POST - 200 - req_time: 0.140253/Sec [2019/06/16 17:45:38] - ::1 - ::1 - /ips - POST - 200 - req_time: 0.288286/Sec
local httpd = require "httpd" local json = require "json" local app = httpd:new("httpd") app:api('/ip', function(content) local httpc = require "httpc" local args = content.args if not args or not args['ip'] then return json.encode({ code = 400, msg = "錯誤的接口調用方式", data = json.null, }) end local code, response = httpc.get("http://freeapi.ipip.net/"..args["ip"]) if code ~= 200 then return json.encode({ code = 401, msg = "獲取數據失敗", data = json.null, }) end return response end) app:api('/ips', function(content) local httpc = require "httpc.class" if not content.json then return json.encode({ code = 400, msg = "錯誤的調用參數", data = json.null, }) end local args = json.decode(content.body) if type(args) ~= 'table' or type(args['ip_list']) ~= 'table' then return json.encode({ code = 400, msg = "錯誤的參數類型", data = json.null, }) end local hc = httpc:new {} local ret = { code = 200 , data = {}} for _, ip in ipairs(args['ip_list']) do local code, response = hc:get("http://freeapi.ipip.net/"..ip) ret['data'][#ret['data']+1] = json.decode(response) end hc:close() return json.encode(ret) end) app:api('/ips_multi', function (content) local httpc = require "httpc" if not content.json then return json.encode({ code = 400, msg = "錯誤的調用參數", data = json.null, }) end local args = json.decode(content.body) if type(args) ~= 'table' or type(args['ip_list']) ~= 'table' then return json.encode({ code = 400, msg = "錯誤的參數類型", data = json.null, }) end local requests = {} local responses = { code = 200, data = {}} for _, ip in ipairs(args["ip_list"]) do requests[#requests+1] = { domain = "http://freeapi.ipip.net/"..ip, method = "get", } end local ok, ret = httpc.multi_request(requests) for _, res in ipairs(ret) do responses['data'][#responses['data'] + 1] = res end return json.encode(responses) end) app:listen("", 8090) app:run()
下一章節咱們將學習如何使用httpd庫編寫Websocket.