HTTPD

2019-04-02 11:43 更新

http parser哪家強(qiáng)?

首先介紹下目前市面上比較知名的2種C實(shí)現(xiàn)的http parser :

  1. h2o的picohttp;

  1. nodejs實(shí)現(xiàn)http_parser;

在cf框架未成形之初! 作者為了測(cè)試簡(jiǎn)單與方便, 自己用string庫(kù)封裝了基礎(chǔ)的http server. 這可以在最初的提交代碼找到.

當(dāng)開(kāi)發(fā)進(jìn)展到底層代碼封裝完畢后, 所以就想到去開(kāi)發(fā)者交友網(wǎng)站進(jìn)行咨詢了解.

目前需求為對(duì)線性字符串匹配與header頭部start與end poosition定位, 然后創(chuàng)建指定大小table組裝http content.

然后針對(duì)性的進(jìn)行數(shù)據(jù)解析, 判斷方法類(lèi)型、打上數(shù)據(jù)類(lèi)型標(biāo)簽, 最后返回給使用者.

在明確上述需求后, 經(jīng)過(guò)一些簡(jiǎn)單調(diào)研與測(cè)試便選擇了h2o的http parser實(shí)現(xiàn).

為什么選擇pico?

原因:

  1. pico的頭文件與實(shí)現(xiàn)代碼就2個(gè)文件, 使用也非常方便, 編譯完成后就可以開(kāi)始使用.

  1. 實(shí)現(xiàn)簡(jiǎn)單并且通俗易懂, 非常容易上手;

  1. pico性能確實(shí)高;

當(dāng)初簡(jiǎn)單對(duì)pico與http_parser進(jìn)行過(guò)對(duì)比, 在不開(kāi)啟sse4的情況下至少快2倍左右。有興趣可以自行測(cè)試.

pico的代碼我放在luaclib內(nèi), 封裝后使用makefile編譯lua可用動(dòng)態(tài)庫(kù). 默認(rèn)沒(méi)開(kāi)啟sse4, 為了照顧一些同學(xué)機(jī)器不支持sse4指令集的情況, 省卻了改makefile的麻煩 :)

中間件設(shè)計(jì)

眾所周知, 中間件設(shè)計(jì)的目的是為了授權(quán)驗(yàn)證、請(qǐng)求準(zhǔn)入等需求設(shè)計(jì)而來(lái)的. 在大多數(shù)http server框架中都會(huì)增加類(lèi)似設(shè)計(jì).

cf為此分離除了before函數(shù)專(zhuān)門(mén)用來(lái)處理httpd service使用, 避免冗余無(wú)用的參數(shù)驗(yàn)證等代碼與業(yè)務(wù)邏輯耦合在一起.

同時(shí), 提供了http庫(kù)來(lái)體現(xiàn)before回調(diào)函數(shù)應(yīng)該如何工作. 在使用者熟練之后可以使用cf很輕松的寫(xiě)出高性能api service.

httpd 使用

下面著重為大家介紹httpd的使用與相關(guān)函數(shù)原型, 有能力的同學(xué)也可以直接閱讀源碼進(jìn)行學(xué)習(xí):

local httpd = require "httpd"

使用之前先導(dǎo)入httpd庫(kù)

httpd:new()

使用new方法創(chuàng)建一個(gè)httpd對(duì)象.(這沒(méi)什么好說(shuō)的)

此方法返回一個(gè)httpd對(duì)象;

httpd:timeout(number)

timeout方法設(shè)置每個(gè)http請(qǐng)求的connection最大保持時(shí)間, 默認(rèn)為15秒;

此方法返回值為nil;

httpd:server_name(string)

server_name方法的參數(shù)是一個(gè)字符串類(lèi)型的參數(shù), 這個(gè)方法設(shè)置cf的http response頭部Server字段的值;

此方法返回值為nil;

httpd:max_path_size(number)

max_path_size方法設(shè)置最大path路徑長(zhǎng)度, 超過(guò)number大小的path都會(huì)被禁止; 默認(rèn)長(zhǎng)度為1024;

此方法返回值為nil;

httpd:max_body_size(number)

max_body_size方法設(shè)置最大body長(zhǎng)度, 超過(guò)number大小的body都會(huì)被禁止; 默認(rèn)長(zhǎng)度為1024 * 1024;

此方法返回值為nil;

httpd:max_header_size(number)

max_header_size方法設(shè)置最大body長(zhǎng)度, 超過(guò)number大小的header都會(huì)被禁止; 默認(rèn)長(zhǎng)度為65535;

此方法返回值為nil;

httpd:before(function)

before方法設(shè)置每個(gè)請(qǐng)求在被業(yè)務(wù)函數(shù)處理之前, 優(yōu)先被function處理.

此方法需要配合http庫(kù)進(jìn)行使用, http可以為此設(shè)計(jì)了專(zhuān)門(mén)的API來(lái)語(yǔ)義化中間件設(shè)計(jì). 提升代碼可讀性.

這個(gè)方法一般可用于設(shè)計(jì)業(yè)務(wù)中間件、準(zhǔn)入認(rèn)證、行為收集等等; 具體使用方法參見(jiàn)main.lua示例.

    local http = require "http"


    app:before(function(content)
        if content.METHOD == 'GET' then
            return http.ok()
        end
        return http.throw(401, '<h1>未授權(quán)</h1>')
    end)

需要注意的是: 只要你注入了funtion, 即使function內(nèi)部什么都不做也會(huì)返回401.

此方法返回值為nil;

httpd:ws(route, handle)

ws方法為使用者注入http -> websocket類(lèi)型的路由升級(jí).

注冊(cè)此方法后, httpd在檢測(cè)到當(dāng)前路由類(lèi)型為ws類(lèi)型后將會(huì)為檢查請(qǐng)求頭部(header), 錯(cuò)誤的頭部將會(huì)被判斷并返回錯(cuò)誤碼.

首先被回調(diào)的是注冊(cè)ws路由的class ctor方法; 這個(gè)方法將會(huì)有一個(gè)opt參數(shù)(table類(lèi)型). ws對(duì)象將會(huì)被注入其中.

具體使用示例, 請(qǐng)參考script/ws.lua.

httpd:use(route, handle)

httpd:api(route, handle)

use/api方法為route注入路由處理函數(shù), handle即可以是一個(gè)函數(shù), 也可以是一個(gè)lua table(class).

注意:

  1. 無(wú)關(guān)乎handle的類(lèi)型, handle的返回值必須為string類(lèi)型作為body返回給客戶端;

  1. api的content-type為Applicaton/json; use則為:text/html;

  1. http庫(kù)不可在此handle內(nèi)部使用, 否則會(huì)出現(xiàn)異常;

如果注入的handle為table:

① 必須使用cf框架內(nèi)置的lua class語(yǔ)法進(jìn)行設(shè)計(jì);

② new方法會(huì)傳入http request content(注意: 構(gòu)造函數(shù)異常將會(huì)引起路由對(duì)應(yīng)的方法無(wú)法被正確調(diào)用);

③ get/post/put方法會(huì)根據(jù)用戶請(qǐng)求類(lèi)型(method)被回調(diào)(無(wú)參數(shù)), 如未實(shí)現(xiàn)對(duì)應(yīng)方法將會(huì)有框架返回對(duì)應(yīng)狀態(tài)碼;

如果注入的handle為function:

cf會(huì)為此function注入當(dāng)前的http request content, 內(nèi)部包含所有請(qǐng)求上下文與參數(shù);

handle返回值必須為一個(gè)string類(lèi)型的值, 否則將可能出現(xiàn)警告或返回空值;

方法返回值為nil

httpd:group(type, prefix, handles)

group方法提供了一種批量注冊(cè)路由的方式, 為一組同一組路由提供簡(jiǎn)單便方便在注冊(cè)方法.

第一個(gè)參數(shù)type為需要批量注冊(cè)的路由類(lèi)型; 初始化httpd對(duì)象后, 使用app.USEapp.API進(jìn)行傳值;

第二個(gè)參數(shù)prefix為string類(lèi)型的頭部; 例如:/api/admin;

第三個(gè)參數(shù)為一組路由處理函數(shù)或處理類(lèi)數(shù)組; 類(lèi)型為: {route = '/login', class = class};

注意: 此方法主要為批量注冊(cè)api類(lèi)型或use類(lèi)型路由對(duì)象準(zhǔn)備, 不可同時(shí)注冊(cè)不同類(lèi)型路由, 不可同時(shí)注冊(cè)websocket路由;

為了模塊化view類(lèi)型路由與api類(lèi)型路由(區(qū)分admin/api類(lèi)型), 提供方便項(xiàng)目管理與使用, 減少潛在口頭的約定;

此方法返回值為nil

httpd:listen(ip, port)

listen方法用于告訴httpd對(duì)象監(jiān)聽(tīng)指定端口; 第一個(gè)參數(shù)ip暫未被httpd使用, 默認(rèn)監(jiān)聽(tīng)所有網(wǎng)卡的ip地址與port端口號(hào);

此方法需要在run方法之前被調(diào)用.

此方法返回值為nil

httpd:run(ip, port)

run方法用于開(kāi)始監(jiān)聽(tīng)模式.

注意: run方法被調(diào)用后, 寫(xiě)在run方法之后的代碼將直到程序結(jié)束后都可能(maybe)不會(huì)被執(zhí)行.

此方法返回值為nil

httpd示例:

一個(gè)最簡(jiǎn)單的cf web service使用示例:

  local httpd = require "httpd"
  local app = httpd:new('httpd')


  app:use('/view', function(content)
    return '<h1>CF Web Service</h1>'
  end)


  app:api('/api', function(content)
    return '{"code":200,"message":"ok"}' -- json string
  end)


  app:listen("0.0.0.0", 8080)
  app:run()

httpd 請(qǐng)求日志格式:

  [年/月/日 時(shí):分:秒] - [ip] - [x-real-ip] - [path] - [http code] - [request handle timeline]

httpd request的 content 內(nèi)容

args : 支持標(biāo)準(zhǔn)get或者post的參數(shù), 對(duì)a[1]=1&a[2]=2將會(huì)不會(huì)解析為數(shù)組類(lèi)型; 支持multipart-form傳參;

body : body支持三中類(lèi)型, multipart-form file/post json/post xml/;

header: 原始header數(shù)組, 不會(huì)進(jìn)行header解析;

file : 進(jìn)行multipart-form上傳一個(gè)或多個(gè)文件時(shí), 才會(huì)有這個(gè)屬性;

cf會(huì)將后兩種數(shù)據(jù)交換格式根據(jù)post content-type類(lèi)型在content內(nèi)注入類(lèi)型標(biāo)識(shí); 如:

  app:use('/admin', function(content)
    if conten.json then
      return 'json', print('json')
    elseif conten.xml then
      return 'xml', print('xml')
    end
    return '未知類(lèi)型'
  end)

注意

body為```xml```或```json```類(lèi)型時(shí), 框架僅會(huì)判斷類(lèi)型做好標(biāo)識(shí), 為了不依賴(lài)相關(guān)庫(kù)所以不會(huì)主動(dòng)解析.
以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)