一、基本介绍


httpd库是一个web服务器套件, 基于HTTP/1.1协议实现而来; 内置了高性能的http协议解析器与urldecode解析库.

httpd库在内部封装了标准路由处理能力, 也提供了一套静态文件读取能力, 这样能为使用者提供全方位的开发套件服务;

httpd库具有高效的短连接快速响应能力与海量长连接保持能力; 内部的Websocket实现基于RFC-6544RFC-7692;

二、基础API


使用之前需要先导入httpd库, local httpd = require "httpd"

1. httpd:new


函数原型: httpd:new()

使用new方法创建一个httpd对象, 此方法返回一个默认的httpd对象;

2. httpd:max_path_size


函数原型: httpd:max_path_size(size)

将参数size的值设置path的最大长度, 实际请求来临的时候超过这个值httpd将会返回414. (默认值为: 1024)

此类型方法不会有任何返回值;

3. httpd:max_header_size


函数原型: httpd:max_header_size(size)

将参数size的值设置header的最大长度, 实际请求来临的时候超过这个值httpd将会返回431. (默认值为: 65535)

此类型方法不会有任何返回值;

4. httpd:max_body_size


函数原型: httpd:max_body_size(size)

将参数size的值设置body的最大长度, 实际请求来临的时候超过这个值httpd将会返回413. (默认值为: 1024 * 1024)

此类型方法不会有任何返回值;

5. httpd:enable_cookie


函数原型: httpd:enable_cookie()

此方法将会开启use路由的cookie解析, 默认情况下是关闭的. 此方法的作用是为了让adimin库可以正常使用;

如果您在使用admin库的时候无法成功登陆, 请尝试调用此方法;

此类型方法不会有任何返回值;

6. httpd:cookie_secure


函数原型: httpd:cookie_secure(secure)

此方法设置cookie密匙, 设置之前请先开启enable_cookie;

secure参数推荐设置一个复杂的值(至少10-20个字符), 因为它决定了你的cookie内容是否安全;

此类型方法不会有任何返回值;

7. httpd:before


函数原型: httpd:before(function)

此方法注册了一个function参数过滤器; 参数function是一个回调函数, 所有的APIUSE路由之前会先调用它;

此类型方法不会有任何返回值;

8. httpd:api


函数原型: httpd:api(route, apiHandle)

此方法为route所在的路由注入回调函数, apiHandle即可以是一个函数或者lua table(class)(很少用).

此类型方法不会有任何返回值;

9. httpd:use


函数原型: httpd:use(route, useHandle)

此方法为route所在的路由注入回调函数, useHandle即可以是一个函数或者lua table(class)(很少用).

此类型方法不会有任何返回值;

10. httpd:ws


函数原型: httpd:ws(route, wsHandle)

此方法为route所在的路由注入Websocket协议回调, 内部会自动完成HTTP/1.1 -> Websocket的协议升级;

在客户端连接成功完成协议升级后, 会触发ctor -> on_open 的方法调用; 当最后的on_open方法被调用后握手流程完成;

在上面提到的方法中, 请不要做任何阻塞或者同步非阻塞调用; 否则在大量频繁连接与销毁场景下会造成连接缓慢等问题;

此类型方法不会有任何返回值;

11. httpd:static


函数原型: httpd:static(folder, ttl)

folder参数定义了静态文件路由的查找目录, ttl参数为静态文件是否有缓存周期. 默认情况下未开启static路由;

ttl参数默认为永不缓存静态文件; 在开发者手动修改ttl后, 浏览器再次访问相同的资源时会优先从本地读取.

此类型方法不会有任何返回值;

12. httpd:listen


函数原型: httpd:listen(ip, port, backlog)

listen方法用于告诉httpd对象监听指定端口, ip指定为"0.0.0.0"即可, port则为你想监听的端口号.

合理的设置backlog能减少连接被重置的情况(默认值为128).

此类型方法不会有任何返回值;

13. httpd:listen_ssl


函数原型: httpd:listen_ssl(ip, port, backlog, key, cert, pw)

listen_ssl方法用于告诉httpd对象监听指定端口, ip指定为"0.0.0.0"即可, port则为你想监听的端口号.

keycert指定私钥与证书所在的文件路径, 不配套的证书与私钥怎会抛出异常. 如果证书有密码则需要配置pw.

合理的设置backlog能减少连接被重置的情况(默认值为128).

14. httpd:listenx


函数原型: httpd:listenx(unix_domain_path, backlog)

listenx方法用于告诉httpd对象监听指定unix domain socket(本地套接字).

合理的设置backlog能减少连接被重置的情况(默认值为128).

15. httpd:enable_rest


函数原型: httpd:enable_rest()

调用后httpd将会开启rest语法支持, 所有rest语法的匹配到的参数将会放在HTTP Contentquery属性上.

基本语法如下所示:


--- 语法①
app:api("/article/{number:id}.html", function(content)
  --- TODO
end)

--- 语法②
app:api("/article/{string:id}.html", function(content)
  --- TODO
end)

--- 语法③
app:api("/article/{id}.html", function(content)
  --- TODO
end)

--- 语法④
app:api("/nlist/{number[]:nlist}", function(content)
  --- TODO
end)

--- 语法⑤
app:api("/slist/{string[]:slist}", function(content)
  --- TODO
end)

语法①的idNumber类型, 如果你需要的是Integer. 那么请自行进行转换.

语法②与③的idString类型, 它可以是任何合理的字符串. 语法③只是语法②的一种简写.

语法④与⑤的nlistslist均为table类型, 内部会自动转换成指定类型数组.

注意:

  • 不建议大规模使用rest语法(性能一般), 如无特殊情况请不要开启支持;

  • 不建议使用④与⑤语法, 因为并不知道客户端传来的数据是否"合理";

16. httpd:log


函数原型: httpd:log(filename)

log方法用来设置日志需要记录filename文件内, 默认情况下框架不会讲日志写入到磁盘文件内;

17. httpd:nolog


函数原型: httpd:nolog(disable)

nolog方法用来关闭httpd库除启动日志外的所有日志信息, 这可能会提升httpd库的整体请求处理效率;

18. httpd:enable_gzip


函数原型: httpd:enable_gzip()

enable_gzip方法用来开启框架响应请求的时候, 是否需要对响应内容进行压缩; 默认情况下是关闭的;

目前框架支持两种响应压缩算法: gzipdeflate;

19. httpd:enable_error_pages


函数原型: httpd:enable_error_pages()

enable_error_pages方法用来开启框架响应错误的时候应该使用内部的错误页面; 默认情况下在发生错误的时候不会有任何内容;

开启后会使用内部的一些页面来浏览器中提示用户响应的错误码, 例如: 500, 505, 413, 431等等;

20. httpd:enable_cros


函数原型: httpd:enable_cros(timeout)

enable_cros用来开启跨域支持, 但是默认情况下是被关闭的;

当框架前置有网关和负载均衡器时, 应该在网关上设置以便统一管理; 提供这种配置的原因是可以方便开发和独立运行的时候使用;

因为框架对跨域配置支持有限, 开启跨域后造成的安全限制大大降低; 除非有必要, 否则并不建议在框架层配置;

三、日志格式


[年/月/日 时:分:秒] - [ip] - [x-real-ip] - [path] - [method] - [http code] - [request timeline]

四、中间件


中间件在定义了软件(框架)层与业务层之间的一系列行为, 提供了一种非入侵的一种方式来实现对处理流程的改造;

httpd库为了实现中间件设计模式而提供了httpd:before方法, 使用者可以根据实际情况来决定是否使用此方法;

五、请求内容


每个http请求来临的时候都会在调用路由回调时为其传入一个Content, 这个Content里包含了请求相关的一些内容.

1.args属性


当客户端发送的请求包含以下情况的时候, Content参数会包含args属性, 例如:

  • 使用GET方法发出请求, 并且url后缀带有?a=1?a=1&b=2的查询请求.

  • 使用POST方法发出请求, 并且body不为空且带有?a=1?a=1&b=2的查询请求.(Content-Type必须为application/x-www-form-urlencoded)

2.header属性


当客户端的请求来临的时候, 此属性会包含所有请求所携带头部信息. 不接受空的头部信息.

3.body属性


body属性会在多种情况下出现, 并且内容由不同请求类型决定. 例如: 请求方法、请求体类型;

下面我们来看下不同请求方法中body的不同 :

  • 当请求方法为GET的时候, body始终为nil(不存在);

  • 当请求方法为POST并且存在Content.xmlContent.json任何一种属性的时候body会存在(但是不会被框架解析);

  • 当请求方法为PUT的时候body可能会存在, 但是不会有任何意义上的标志表示body可能是某种类型;

4. files


当客户端使用multipart/form-data传递数据到服务端时, 请求头部中将会有这个属性; 此属性专门用来存储上传文件的内容;

值得注意的是, 这个属性是数组类型; 并且服务端不能假设上传的数据内容一定真实;

六、请求过滤


当我们使用路由过滤回调注册作为中间件的时候, 我们可能会思考应该怎么使用它?

下面我们介绍几个内置库提供的方法, 来帮助大家编写一些简单的过滤器代码:

1. http.ok


当在before方法注册的回调函数返回http.ok()后, 允许后续继续调用用户注册的路由回调函数.

你也可以直接写return 200来替代http.ok(), 他们的结果是一样的;

2. http.redirect(code, url)


当在before方法注册的回调函数返回http.redirect(301, 'https://cfadmin.cn/')后, 则将请求重定向到指定链接上;

注意:

  • 参数code只能是301302303307308的其中一个;

  • 参数url则必须以https/http/开头;

3. http.throw(code, html)


当在before方法注册的回调函数返回http.throw(404, "<title>错误</title>")后, 将使用指定的code状态码来进行返回(仅允许400-600之间的错误码);

第二个参数为可选的html代码, 作为自定义错误码的内容(可以在调试阶段将错误日志打印出来).

如果不提供html参数, 将会根据是否配置了error_pages决定输出结果;

七、httpd包装器

以下涉及到的方法都在httpd目录下, 请自行根据实际情况引用.

1. 异常包装器

function Throw(code, response) end

让注册的USEAPI路由可以合法的抛出异常.

  • code - HTTP状态码(400-600).

  • response - 异常附带的响应体.

2. 跳转包装器


function redirect(code, url) end

让注册的USEAPI路由可以合法的重定向.

  • code - HTTP状态码(301/302/303/307/308).

  • url - 合法的重定向的URL.

3. 响应包装器


  • [x] function file_response(filename, filetype, fileinline) end

    让注册的USEAPI路由可以将文件包装为一个响应, 告知httpd并响应给客户端.

  • filename- string类型, 指定合法且完整的文件路径(如: static/index.html)

  • filetype- string类型, 指定合法且完整的文件类型(如: text/css)

  • fileinline- boolean类型, 指定响应的文件是否需要内嵌到浏览器.

  • [x] function text_response(ctext, ctype) end

    让注册的USEAPI路由可以将ctext字符串包装为一个响应, 告知httpd并响应给客户端.

  • ctext- string类型, 合法且完整的响应内容(如: <html>Hello World.</html>)

  • ctype- string类型, 合法且完整的响应类型(如: text/html)

八、示例


最后, 我们给出一个简单的示例以供大家自由扩展与调试.

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

local http = require "httpd.http"

-- 异常包装器
local http_throw = require "httpd.Throw"

-- 跳转包装器
local http_redirect = require "httpd.Redirect"

-- 响应包装器
local http_response = require "httpd.Response"
-- 文件类型
local file_response = http_response.file_response
-- 文本类型
local text_response = http_response.text_response

require "utils"

app:before(function (content)
  if true then
    return http.ok()
  end
  --[[
  if true then
    return http.redirect(301, 'https://cfadmin.cn/')
  end
  if true then
    return http.throw(431, '<h1> This is 413 Error, too long request header</h1>')
  end
  --]]
end)

app:api("/api", function (content)
  return http_throw(505, '{"code":505,"msg":"请求失败"}')
end)

app:api("/redirect", function (content)
  return http_redirect(302, "/api")
end)

--[[ 访问:/error/内部服务器错误 ]]
app:use("/error/{info}", function (content)
  return http_throw(500, "错误: " .. content.query.info)
end)

--[[ 访问:/jump/www.baidu.com 重定向到`https://www.baidu.com` ]]
app:use("/jump/{url}", function (content)
  return http_redirect(301, "https://" .. content.query.url)
end)

--[[ 访问:/view/static/index.html 会响应`static`文件夹下的`index.html` ]]
app:use("/view/static/{name}.html", function (content)
  return file_response("static/" .. content.query.name .. ".html", "text/html")
end)

--[[ 访问:/static/welcome.html, 将会改编content-type为application/json ]]
app:use("/test/{id}", function (content)
  return text_response('{"id":[1,2,3]}', "application/json")
end)

app:enable_rest()

app:listen("0.0.0.0", 8080)

app:run()

九、结束


以上为luahttpd使用内容.

Copyright © CandyMi 2019-2022 all right reserved,powered by Gitbook该文件修订时间: 2021-08-27 20:18:00

results matching ""

    No results matching ""