httpserver
简介
一个基于 gs 实现的简单 http 服务器
允许跨域
建立一个filter, 加入相关头设置参数
import pkg.httpserver.request;
import pkg.httpserver.response;
component pkg.httpserver.abstract_filter;
public override bool abstract_filter.forward(request req, response res)
{
res.set_header("Access-Control-Allow-Origin: " + (req.get_header("origin") ?? "") + "\r\n");
res.set_header("Access-Control-Allow-Headers: content-type\r\n");
res.set_header("Access-Control-Allow-Credentials: true\r\n");
return true;
}
public override bool abstract_filter.backward(request req, response res)
{
return true;
}
连接管理
建立连接
确定监听端口后, gs
内置方法, 创建监听socket
, 从而调用socket.accept()
来与客户端建立连接.
长连接
当http
的请求头中携带Connection: keep-alive
时, 保持长连接. 连接保持时间为connection_timeout_(httpserver)
.
在每个新的连接进来之后, 会创建两个协程, 一个协程用于处理业务, 一个协程用于关闭连接(长时间没有新的请求);
处理流程
整个处理流程, 采用分层的链式处理, 具体处理流程见流程图
从socket读取数据
直接调用socket函数recv(int)
函数
放序列化数据
主要更具http
协议, 对http
的请求头以及内容进行相应处理, 将其封装到request
中, 方便业务处理
过滤器
过滤器主要是为了切面编程的需要. 所有url都需要通过过滤器, 默认没有过滤器, 过滤可以通过配置 文件中的filters
进行配置
支持 magic url
支持将 /a/:id/:a
这种路径绑定到一个函数上,其中 id
和 a
会被绑定到 req
的 query 中
主要可以用来处理日志以及权限验证, 也可以用来对数据验证以及模型绑定.
过滤器的形式
public virtual bool forward(request req, response res)
{
}
public virtual bool backward(request req, response res)
{
}
函数处理
将指定url绑定到指定的函数进行处理, 可以通过以下函数进行绑定:
"urls":[
{
"url": "/",
"handle": "/test/test.gs@home"
}
]
handle
中通过@
分离文件名和方法名
- 在代码中动态添加
httpserver.add_handler("/add", (: add :));
httpserver.add_dir_handler("/abc", "/test/", "test.gs");
httpserver.add_file_handler("/a", "/test/test.gs");
组件接口
httpserver.gs
函数原型 | 函数作用 |
---|---|
void start(string name = "httpserver", mixed config_file = "/etc/server.json") | 启动默认服务器 |
object listen(int port) | 启动一个新的服务器实例, 用于监听与默认服务器不同的端口 |
int get_port() | 获取服务器监听端口号 |
void add_handler(string url, function func) | 绑定 url |
void add_file_handler(string url, mixed obj, string pattern = ".*") | 将一个 objcet 全部满足 pattern 的函数绑定到 url + 方法名上 |
void add_dir_handler(string url, string path, string file_pattern = ".", string method_pattern = ".") | 一个文件夹下的满足 file_pattern 的文件中, 满足 method_pattern 的方法绑定到 url + file_name + method_name 上 |
void load_assets() | 重新加载静态资源 |
request.gs
函数原型 | 函数作用 |
---|---|
string get_method() | 获取请求方法 get, post, put ... |
string get_host() | 获取请求 header 里面对应的 host |
buffer get_content() | 获取 post / put 请求中的请求总体的内容 |
mixed get_url() | 获取正在处理的 url |
string get_peer_ip() | 获取请求对方的 ip |
mixed get_headers() | 获取所有请求头 |
mixed get_querys() | 获取所有请求参数, 包括 url 以及 请求主体的 |
void set_session_value(string key, mixed val) | 设置 session value |
mixed get_session_value(string key) | 获取 session 的值 |
mixed get_query(string key) | 获取指定名称的参数 |
mixed get_header(string key) | 获取指定名称的header |
response.gs
函数原型 | 函数作用 |
---|---|
void add_header(string key, mixed val) | 添加 header 值 |
void add_cookie(string key, string val) | 添加 cookie 值 |
void set_content_type(int type) | 设置返回内容的类型, 参考 Content_Type |
void set_res_code(int code) | 设置请求状态码, 默认 200 |
void set_content(mixed val, int content_type = -1) | 设置返回给客户端的内容 |
枚举
Response_Code
switching_protocols = 101,
ok = 200,
created = 201,
accepted = 202,
no_content = 204,
partial_content = 206,
multiple_choices = 300,
moved_permanently = 301,
moved_temporarily = 302,
not_modified = 304,
temporary_redirect = 307,
bad_request = 400,
unauthorized = 401,
forbidden = 403,
not_found = 404,
internal_server_error = 500,
not_implemented = 501,
bad_gateway = 502,
service_unavailable = 503
content_encoding
gzip,
none
Content_Type
rep_buffer,
rep_html,
rep_json,
rep_string,
rep_multipart,
rep_css,
req_urlencoded
Header_Attr
rep_keep = 1 << 0,
rep_close = 1 << 1,
rep_len = 1 << 2,
rep_server = 1 << 3,
rep_set_cookie = 1 << 4
样例
#pragma parallel
import pkg.httpserver;
import pkg.httpserver.request;
import pkg.httpserver.response;
void create()
{
// /add 会被 (: add :) 处理
httpserver.add_handler("/add", (: add :));
// /abc/add_server/add 会被 (: add :) 处理
httpserver.add_dir_handler("/abc", "/sample/", "add_server.gs");
// /a/add 会被 (: add :) 处理
httpserver.add_file_handler("/a", "/sample/add_server.gs");
}
public void add(request req, response res)
{
res.set_content("using code to add handler");
}
// 加载服务器
httpserver.start("test server", "/etc/server.json");
// httpserver.start();