跳到主要内容

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 这种路径绑定到一个函数上,其中 ida 会被绑定到 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中通过@分离文件名和方法名

  1. 在代码中动态添加
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();