V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
爱意满满的作品展示区。
monkeyNik
V2EX  ›  分享创造

分享一个自己开源的 HTTP API 服务器

  •  
  •   monkeyNik ·
    Water-Melon · 2023-07-28 10:07:28 +08:00 · 498 次点击
    这是一个创建于 488 天前的主题,其中的信息可能已经有所发展或是发生改变。

    本文是一款介绍开源 API 服务器Medge的文章。Medge 是一个 HTTP 服务器,目前将其定位为 API 服务器方向。

    在 Medge 中,我们可以通过脚本语言Melang来编写和实现 API 逻辑。Melang 是一种抢占式调度的协程语言,其每一个脚本任务都被视为一个协程运行在同一个单一线程内部,依据执行步长轮询调度。因此,在上层逻辑开发过程中,开发者无需考虑协程调度问题,也就无需考虑何时该调用某些特定函数让出 CPU 执行权。

    下面我们进入正题,看一个完整的简单使用示例。

    使用示例

    当我们安装好 Medge 后,我们可以在命令行中输入

    $ medge
    

    来启动 HTTP 服务器。

    我们使用如下命令参数来启动 Medge:

    $ medge -p 8080 -d /opt/medge/ -w 1
    

    这里,

    • -p 是用于指定该 HTTP 服务器监听的 TCP 端口号,若不设置默认为 80 。本例中 HTTP 监听0.0.0.0:8080
    • -d 是用于指定 API 服务的统一入口目录路径,本例中是/opt/medge。我们稍后会对这个目录下的结构进行说明。若不指定本参数项,则默认为/opt/medge
    • -w 是用于指定 HTTP 的工作进程数。若不指定默认为1

    此时,服务器已经启动了,但是我们还没有给出 API 服务的具体处理逻辑。那么下面我们就来增加 API 服务。

    上面提到了 Medge 的-d参数指定了 API 服务的统一入口目录,下面我们就给出这一路径下的大致目录树结构:

    |- /opt/medge/
        |- service_1/
            |- entry.m
            |- ...
        |- service_2/
            |- entry.m
            |- ...
    

    可以看到,在/opt/medge目录下,存在两个服务,即:service_1service_2,且每个服务下都有一个同名脚本文件entry.mentry.m是服务的入口文件,即当 Medge 收到 HTTP 请求,找到对应服务后,就会立刻执行该服务的entry.m脚本进行处理。

    在我们的这个示例中,我们仅演示一个 API 服务,因此本例中的目录树结构为:

    |- /opt/medge/
        |- 127.0.0.1:8080/
            |- entry.m
            |- index.m
    

    这里,127.0.0.1:8080是一个目录,之所以起这样的名字,是因为 Medge 中的服务名是以 HTTP 请求的 Host 命名和区分的。因为本例不存在使用域名发起 HTTP 请求,所以这里的目录名称就是这样一个 IP+端口的形式。

    下面,我们给出entry.mindex.m的脚本内容:

    //entry.m
    /*
     * Implement a simple controller.
     * There are three variable injected in this script task:
     *   1. Req. Its prototype is:
     *       Req {
     *           method; //string  e.g. GET POST DELETE ...
     *           version; //string e.g. HTTP/1.0 HTTP/1.1
     *           uri; //string e.g. /index/index
     *           args; //an key-value array, e.g. ["key":"val", ...]
     *           headers; //an key-value array, e.g. ["Content-Type":"application/json", ...]
     *           body; //string
     *       }
     *
     *    2. Resp. Its prototype is:
     *        Resp {
     *            version; //same as Req's version
     *            code; //integer  e.g. 200
     *            headers; //same as Req's headers
     *            body; //same as Req's body
     *        }
     *
     *.   3. Basedir. A string of the base directory path. (Not used in this example)
     */
    
    #include "@/index.m"
    
    str = Import('str');
    sys = Import('sys');
    
    uri = str.slice(Req.uri, '/');
    ctlr = str.capitalize(uri[0]);
    o = $ctlr;
    if (sys.has(o, uri[1]) != 'method') {
      Resp.code = 404;
    } else {
      o.__action__ = uri[1];
      Resp.body = o.__action__();
      Resp.headers['Content-Length'] = str.strlen(Resp.body);
    }
    
    //index.m
    
    Json = Import('json');
    
    Index {
        @index() {
            Resp.headers['Content-Type'] = 'application/json';
            return Json.encode(['code': 200, 'msg': 'OK']);
        }
    }
    

    可以看到,entry.m前面包含了一些注释信息,其中提到,每个请求都会向其对应服务的entry.m脚本中注入 3 个变量:

    • Req 包含了请求有关的信息,如:方法、版本、资源路径、参数、请求头和请求体。
    • Resp 包含了响应有关的信息,如:版本(默认与请求版本一致)、响应状态码(默认为 200 )、响应头和响应体。
    • Basedir 是一个字符串,内容为 Medge -d参数指定的路径。

    简单来说,本例中的entry.m实现了一个非常简单的 MVC 框架中的控制器,它根据资源路径找到对应的处理类和类方法,并调用它们来处理 HTTP 请求。

    本例中,我们将使用如下命令发起 HTTP 请求:

    $ curl -v http://127.0.0.1:8080/index/index
    

    所以,entry中会先对资源路径/index/index进行切片,获取第一个index后将其首字母大写。随后使用这个修改后的字符串作为类名,查找当前脚本环境中是否存在一个名为Index的类。找到后,调用其index(即资源路径的第二个 index )方法处理请求。

    在执行curl命令后,我们将看到其输出大致为:

    *   Trying 127.0.0.1:8080...
    * Connected to 127.0.0.1 (127.0.0.1) port 8080 (#0)
    > GET /index/index HTTP/1.1
    > Host: 127.0.0.1:8080
    > User-Agent: curl/7.81.0
    > Accept: */*
    > 
    * Mark bundle as not supporting multiuse
    < HTTP/1.1 200 OK
    < Content-Length: 23
    < Content-Type: application/json
    < 
    * Connection #0 to host 127.0.0.1 left intact
    {"code":200,"msg":"OK"}
    

    结束语

    目前 Medge 还只是个实验性项目,其中还有很多功能有待实现,例如目前它只支持 HTTP/1.0 HTTP/1.1 的版本,且暂未支持 https 。除此之外,目前 Melang 脚本仅支持 MySQL 数据库,且还没有对应的 http 库函数或类供开发者使用。

    感兴趣的小伙伴可以访问其Github 仓库

    感谢阅读!

    目前尚无回复
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1127 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 22:55 · PVG 06:55 · LAX 14:55 · JFK 17:55
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.