httpd_plugin
TSL语言的跨平台实现的内建HTTP服务器插件。
安装
(已集成到mytsl
发行版中)
动态库文件:Windows: httpd_plugin.dll 或者 Linux: libhttpd_plugin.so,把动态库文件拷贝TSL目录的plugin目录。
使用指南
提供的TSL函数:
httpd_create
httpd_create(port, [address], [doc_root])
: 创建HTTP服务器。
-
参数列表
参数 描述 port 侦听的端口,整数类型 address 侦听地址,可选参数 doc_root 静态文件根目录,可选参数。如果请求的URL最后是'/',会返回对应目录的index.html文件。 -
返回值
HTTP服务器句柄。
-
例子
httpd_destroy
httpd_destroy(handle)
: 销毁HTTP服务器。
-
参数列表
参数 描述 handle HTTP服务器句柄 -
返回值 无
-
例子
httpd_config_ssl
httpd_config_ssl(handle, cert_file, private_key_file, [password])
: 设置https相关的证书,配置了将会启用https。
-
参数列表
参数 描述 handle HTTP服务器句柄 cert_file 证书文件名 private_key_file 私钥文件名 password 私钥的密码,可选参数 -
返回值
无
-
例子
httpd_route
httpd_route(handle, pattern, func)
:注册URL路由,根据模式匹配调用相应处理函数。
-
参数列表
参数 描述 handle HTTP服务器句柄 pattern 模式 func 函数名 -
返回值
数组类型,如果发生错误:
下标 值 0 错误代码 1 错误信息 没有错误:
下标 值 0 0 1 空 -
例子
httpd_route(httpd, "foo/<int:pk>/", "foo");
httpd_route(httpd, "data/<str:stock>/<int:date>/", "get_stock_data");
模式说明
- 用尖括号从URL中提取值。
- 捕获的值可以选择性地包含转换器类型。比如,使用
<int:name>
来捕获整型参数。如果没有指定转换器,则会匹配除了/
外的任何字符。 - 开头不需要添加反斜杠,因为每个URL都有。比如,应该是
articles
而不是/articles
。
转换器说明
str
- 匹配除了'/'
之外的非空字符串。如果表达式内不包含转换器,则会默认匹配字符串。int
- 匹配 0 或任何正整数。返回一个int
。slug
- 匹配任意由 ASCII 字母或数字以及连字符和下划线组成的短标签。uuid
- 匹配一个格式化的 UUID 。为了防止多个URL映射到同一个页面,必须包含破折号并且字符都为小写。path
- 匹配非空字段,包括路径分隔符'/'
。它允许你匹配完整的 URL 路径而不是像str
那样匹配URL的一部分。
请求处理函数说明
- 函数的第一个参数是HttpRequest对象,接下来的参数按捕获的值的顺序传递。
- 例子
httpd_middleware
httpd_middleware(handle, request_func, response_func)
: 注册中间件,可以对请求和回应进行额外处理。
-
参数列表
参数 描述 handle HTTP服务器句柄 request_func 处理请求的函数名。函数第一个参数request。如果返回NIL会继续处理,可以修改request添加需要的信息。如果返回任何其他内容都会中止处理,返回给用户。 response_func 处理回应的函数名。函数第一个参数request, 第二个参数是response。可以修改response。 -
返回值
数组类型,如果发生错误:
下标 值 0 错误代码 1 错误信息 没有错误:
下标 值 0 0 1 空 -
例子
httpd_middleware(httpd, 'session_process_request', 'session_process_response');
httpd_middleware(httpd, 'cache_process_request', 'cache_process_response');
function session_process_request(request);
begin
// check user login and set sesssion...
request.session_id := "user1";
// 如果返回HttpResponse,将会终止后续处理,立即返回给用户
// 例如如果用户没登录,重定向到登录页面
// 返回不是NIL的都会中止后续处理
return nil;
end;
function session_process_response(request, response);
begin
// 可以修改response
response.set("X-MYTAG", "Hello!");
// 也可以做一些其他处理,例如缓存,清理...
end;
httpd_run_forever
httpd_run_forever(handle, threads)
: 运行HTTPD服务器。
-
参数列表
参数 描述 handle HTTP服务器句柄 threads 线程数,整数类型,可选参数,默认是1,也就是单线程。 -
返回值
数组类型,如果发生错误:
下标 值 0 错误代码 1 错误信息 没有错误:
下标 值 0 0 1 空 -
例子
关于多线程的说明
- 多线程模式可以同时处理多个请求,在有大量高并发请求的场景下会相当有用。
- 对请求处理函数的调用都是独立的,没办法共享变量。
- TODO 提供变量的共享机制。
httpd_shutdown
httpd_shutdown(handle)
: 关闭HTTPD服务器。
-
参数列表
参数 描述 handle HTTP服务器句柄 -
返回值
数组类型,如果发生错误:
下标 值 0 错误代码 1 错误信息 没有错误:
下标 值 0 0 1 空
httpd_wss
httpd_wss(handle, func1, func2, func3)
: 启用websocket服务。
-
参数列表
参数 描述 handle HTTP服务器句柄 func1 websocket消息处理方法 func2 新增websocket连接处理方法 func3 websocket连接断开处理方法 -
返回值
数组类型,如果发生错误:
下标 值 0 错误代码 1 错误信息 没有错误:
下标 值 0 0 1 空 -
例子
h := httpd_create(8000,"0.0.0.0","d:/temp");
// 配置websocket支持
httpd_wss(h, "wss", "wss_join", "wss_leave");
// 同时还可以处理正常的请求
httpd_route(h, "foo/<int:pk>/", "foo");
httpd_run_forever(h);
httpd_destroy(h);
// 收到websocket消息的处理方法
function wss(session, msg)
begin
println("msg={}", msg);
return exportjsonstring(array("msg":msg)); // 返回的消息将会发送出去
end;
// 新增websocket连接处理方法
function wss_join(session, msg)
begin
println("{} join", session);
return exportjsonstring(array("msg":"Welcome!"));
end;
// 断开websocket连接处理方法
function wss_leave(session, msg)
begin
println("{} leave", session);
end;
function foo(request, pk);
begin
println("pk={}",pk);
return new httpresponse(200, fmt("Hello, {}!", pk));
end;
如何编写处理请求的函数
第一个参数是HttpRequest对象,可以通过这个对象获得相关请求的信息。必须返回HttpResponse对象。
HttpRequest对象
属性
属性名 | 说明 |
---|---|
scheme | 请求协议的字符串(通常是 http 或 https)。 |
body | 原始的 HTTP 请求体。 |
path | URL。 |
method | 请求中使用的 HTTP 方法的字符串。例如‘GET’。 |
encoding | 编码的字符串。 |
content_type | 请求的 MIME 类型。 |
headers | 请求头,数组类型。 |
cookies | cookie列表,数组类型 |
自定义属性 | 允许用户设置任何自定义的属性。 |
方法
方法名 | 说明 | 返回值 |
---|---|---|
search_params() | URL中的查询参数。 | 数组类型,例如array('name1':array('value1'))。 |
form_data() | 返回表单的内容,只适用POST请求。 | 数组类型,例如array('name1' : array('value' : array('1'), 'filename' : ... ), ...)。以变量名作为下标,value是数组类型,因为表单可以有多重选项。如果是上传文件,才会有filename这个字段。例如array('name1' : array('filename' : 'a.zip', 'value' : array('PK\x0...))), ...)。 |
HttpResponse对象
属性
属性名 | 说明 |
---|---|
status | HTTP状态码,默认是200。 |
content | 内容。 |
content_type | MIME 类型,默认是'text/html'。 |
headers | 头。 |
方法
方法名 | 说明 | 返回值 |
---|---|---|
set(field, value) | 设置字段,参数field是字段名,value是值,都是字符串类型。例如,res.set("Server", "MyHTTPServer")。支持的字段名参见附录。 | 无返回值 |
set_cookie(value) | 设置cookie,参数是字符串类型,如"name=value" | 无返回值 |
派生类
用户可以通过继承HttqResponse类来实现自定义的Response,例如HttpResponseRedirect来重定向,JsonResponse来返回Json格式的数据。
范例
httpd := httpd_create(8000,"0.0.0.0","d:/temp");
httpd_route(httpd, "foo/<int:pk>/", "foo");
httpd_run_forever(httpd);
httpd_destroy(httpd);
function foo(request, pk);
begin
println("pk={}",pk);
println("headers={}", request.headers);
if request.method() = 'POST' then
println("form={}", request.form_data());
return new HttpResponse(200, "ok");
end;
用浏览器访问地址 http://127.0.0.1:8000/foo/1/ ,浏览器会显示ok。
如何从mod_tsl移植应用
- <?tslx>可以赋值给变量
echo->var
例子:
function myApp(request, name);
begin
s := <?tslx>Hello, <?=name?>!<br></?tslx>;
for x in array(1,2,3).iter() do
echo->s '<br>', 'x=', x, '<br>';
return new HttpResponse(200, s);
end;
附录
Response可以设置的字段
字段名 | 说明 | 例子 | 状态 |
---|---|---|---|
Access-Control-Allow-Origin | 指定哪些网站可参与到跨来源资源共享过程中 | Access-Control-Allow-Origin: * |
临时 |
Accept-Patch | 指定服务器支持的文件格式类型。 | Accept-Patch: text/example;charset=utf-8 |
常设 |
Accept-Ranges | 这个服务器支持哪些种类的部分内容范围 | Accept-Ranges: bytes |
常设 |
Age | 这个对象在代理缓存中存在的时间,以秒为单位 | Age: 12 |
常设 |
Allow | 对于特定资源有效的动作。针对HTTP/405这一错误代码而使用 | Allow: GET, HEAD |
常设 |
Cache-Control | 向从服务器直到客户端在内的所有缓存机制告知,它们是否可以缓存这个对象。其单位为秒 | Cache-Control: max-age=3600 |
常设 |
Connection | 针对该连接所预期的选项 | Connection: close |
常设 |
Content-Disposition | 一个可以让客户端下载文件并建议文件名的头部。文件名需要用双引号包裹。 | Content-Disposition: attachment; filename="fname.ext" |
常设 |
Content-Encoding | 在数据上使用的编码类型。参考 超文本传输协议压缩 。 | Content-Encoding: gzip |
常设 |
Content-Language | 内容所使用的语言 | Content-Language: da |
常设 |
Content-Length | 回应消息体的长度,以 字节 (8位为一字节)为单位 | Content-Length: 348 |
常设 |
Content-Location | 所返回的数据的一个候选位置 | Content-Location: /index.htm |
常设 |
Content-MD5 | 回应内容的二进制 MD5 散列,以 Base64 方式编码 | Content-MD5: Q2hlY2sgSW50ZWdyaXR5IQ== |
过时的 |
Content-Range | 这条部分消息是属于某条完整消息的哪个部分 | Content-Range: bytes 21010-47021/47022 |
常设 |
Content-Type | 当前内容的类型 | Content-Type: text/html; charset=utf-8 |
常设 |
Date | 此条消息被发送时的日期和时间(按照 RFC 7231 中定义的“超文本传输协议日期”格式来表示) | Date: Tue, 15 Nov 1994 08:12:31 GMT |
常设 |
ETag | 对于某个资源的某个特定版本的一个标识符,通常是一个 消息散列 | ETag: "737060cd8c284d8af7ad3082f209582d" |
常设 |
Expires | 指定一个日期/时间,超过该时间则认为此回应已经过期 | Expires: Thu, 01 Dec 1994 16:00:00 GMT |
常设: 标准 |
Last-Modified | 所请求的对象的最后修改日期(按照 RFC 7231 中定义的“超文本传输协议日期”格式来表示) | Last-Modified: Tue, 15 Nov 1994 12:45:26 GMT |
常设 |
Link | 用来表达与另一个资源之间的类型关系,此处所说的类型关系是在 RFC 5988 中定义的 | 常设 | |
Location | 用来 进行重定向,或者在创建了某个新资源时使用。 | Location: http://www.w3.org/pub/WWW/People.html |
常设 |
P3P | 用于支持设置策略,标准格式为“P3P:CP="your_compact_policy" ”。然而P3P规范并不成功,大部分现代浏览器没有完整实现该功能,而大量网站也将该值设为假值,从而足以用来欺骗浏览器的P3P插件功能并授权给第三方Cookies。 |
P3P: CP="This is not a P3P policy! ``See http://www.google.com/support/accounts/bin/answer.py?hl=en&answer=151657 for more info." |
常设 |
Pragma | 与具体的实现相关,这些字段可能在请求/回应链中的任何时候产生多种效果。 | Pragma: no-cache |
常设 |
Proxy-Authenticate | 要求在访问代理时提供身份认证信息。 | Proxy-Authenticate: Basic |
常设 |
Public-Key-Pins | 用于缓解,声明网站认证使用的证书的散列值 | Public-Key-Pins: max-age=2592000; pin-sha256="E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g="; |
常设 |
Refresh | 用于设定可定时的重定向跳转。右边例子设定了5秒后跳转至“http://www.w3.org/pub/WWW/People.html ”。 |
Refresh: 5; url=http://www.w3.org/pub/WWW/People.html |
专利并非标准Netscape实现的扩展,但大部分网页浏览器也支持。 |
Retry-After | 如果某个实体临时不可用,则,此协议头用来告知客户端日后重试。其值可以是一个特定的时间段(以秒为单位)或一个超文本传输协议日期。 | Example 1: Retry-After: 120 Example 2: Retry-After: Fri, 07 Nov 2014 23:59:59 GMT |
常设 |
Server | 服务器的名字 | Server: Apache/2.4.1 (Unix) |
常设 |
Set-Cookie | Set-Cookie: UserID=JohnDoe; Max-Age=3600; Version=1 |
常设: 标准 | |
Status | 通用网关接口 协议头字段,用来说明当前这个超文本传输协议回应的 状态 。普通的超文本传输协议回应,会使用单独的“状态行”("Status-Line")作为替代,这一点是在 RFC 7230 中定义的。 | Status: 200 OK |
Not listed as a |
Strict-Transport-Security | HTTP 严格传输安全这一头部告知客户端缓存这一强制 HTTPS 策略的时间,以及这一策略是否适用于其子域名。 | Strict-Transport-Security: max-age=16070400; includeSubDomains |
常设: 标准 |
Trailer | 这个头部数值指示了在这一系列头部信息由由编码。 | Trailer: Max-Forwards |
常设 |
Transfer-Encoding | 用来将实体安全地传输给用户的编码形式。当前定义的方法包括:分块(chunked)、compress、deflate、gzip和identity。 | Transfer-Encoding: chunked |
常设 |
Upgrade | 要求客户端升级到另一个协议。 | Upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11 |
常设 |
Vary | 告知下游的代理服务器,应当如何对未来的请求协议头进行匹配,以决定是否可使用已缓存的回应内容而不是重新从原始服务器请求新的内容。 | Vary: * |
常设 |
Via | 告知代理服务器的客户端,当前回应是通过什么途径发送的。 | Via: 1.0 fred, 1.1 example.com (Apache/1.1) |
常设 |
Warning | 一般性的警告,告知在实体内容体中可能存在错误。 | Warning: 199 Miscellaneous warning |
常设 |
WWW-Authenticate | 表明在请求获取这个实体时应当使用的认证模式。 | WWW-Authenticate: Basic |
常设 |
X-Frame-Options | 保护:deny :该页面不允许在 frame 中展示,即使是同域名内。sameorigin :该页面允许同域名内在 frame 中展示。allow-from *uri* :该页面允许在指定uri的 frame 中展示。allowall :允许任意位置的frame显示,非标准值。 |
X-Frame-Options: deny |
过时的 |
更多请参见HTTP标准。