用cowboy构建嵌入式Web服务器

最近想用cowboy做一个echo服务器,经过几天的辛苦探索终于实现了,下面记录一下过程,源码等下会上传到Github。

系统:Ubuntu16.04

Erlang版本:20

cowboy版本:2.0.0

1、使用erlang.mk构建OTP release

简单列出一下命令,详细过程可以参考下面的链接。

$ mkdir hello_joe 
$ cd hello_joe
$ wget https://erlang.mk/erlang.mk
make -f erlang.mk bootstrap bootstrap-rel
make

如果编译提示在目录./.erlang.mk/下找不到relx文件,可以再make一下,第一次make会下载relx。

到这里已经构建好了一个基础的OTP release,其他工作可以在此基础上进行。

参考:https://erlang.mk/guide/getting_started.html

           https://ninenines.eu/docs/en/cowboy/2.0/guide/getting_started/  

2、给构建好的OTP release配置cowboy依赖

修改Makefile成下面这样:

PROJECT = echo_server
PROJECT_DESCRIPTION = New project
PROJECT_VERSION = 0.1.0

DEPS = cowboy
dep_cowboy_commit = master

DEP_PLUGINS = cowboy

include erlang.mk

键入make run,会自动下载cowboy及相关依赖到deps目录。

3、监听连接

修改src/echo_server_app.erl:

start(_Type, _Args) ->
        Dispatch = cowboy_router:compile([
                %% {URIHost, list({URIPath, Handler, Opts})}
                {'_', [
                        {"/test2.html", cowboy_static, {priv_file, echo_server, "test2.html"}},
                        {"/cgi", cgi_web_server, []}
                ]}
        ]),
        {ok, _} = cowboy:start_clear(my_http_listener,
                [{port, 8080}],
                #{env => #{dispatch => Dispatch}}
        ),
        echo_server_sup:start_link().

这里最重要的是配置路由表,路由表决定URI路径会映射到哪个处理模块。

cowboy_static是提供一个静态内容,这里将”/test2.html”映射到echo_server的priv目录下的test2.html。

cgi_web_server是我自己定义请求处理模块。

参考http://blog.imaou.com/erlang/2015/02/24/build_web_service_with_cowboy_and_relx_1.html

4、处理请求

用模板生成处理模块:

$ make new t=cowboy.http n=cgi_web_server
然后修改刚生成的处理模块:

cgi_web_server.erl:

-module(cgi_web_server).
-behavior(cowboy_handler).

-export([init/2]).

init(Req, State) ->
    Path = cowboy_req:path(Req),
    handle1(Path, Req, State).
handle1(<<"/cgi">>, Req, State) ->
    ModFunBin = cowboy_req:parse_qs(Req),
    {ok, Bin, Req2} = cowboy_req:read_body(Req),
    Val = mochijson2:decode(Bin),
    Response = call(ModFunBin, Val),
    Json = mochijson2:encode(Response),
    Req3 = cowboy_req:reply(200,
                #{<<"content-type">> => <<"text/plain">>},
                Json, Req2),
    {ok, Req3, State};
handle1(Path, Req, State) ->
    Response = read_file(Path),
    Req1 = cowboy_req:reply(200,
                #{<<"content-type">> => <<"text/plain">>},
                Response, Req),
    {ok, Req1, State}.

call([{<<"mod">>,MB},{<<"func">>,FB}], X) ->
    Mod = list_to_atom(binary_to_list(MB)),
    Func = list_to_atom(binary_to_list(FB)),
    apply(Mod, Func, [X]).

read_file(Path) ->
    File = [$.|binary_to_list(Path)],
    case file:read_file(File) of
        {ok, Bin} -> Bin;
        _ -> ["<pre>cannot read:", File, "</pre>"]
    end.
键入make run启动服务器,然后在浏览器输入localhost:8080/test2.html就可以看到如下显示(没有下面的json文本),点击click显示json格式文本。



说明浏览器收到了来自Erlang发回的数据。

最后附上test2.html的内容:

<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.2.1.min.js"></script>
<h1>Test2</h1>
<button id="button1">click</button>
<div id="result"></div>
<script>
$(document).ready(go);
var data = {int:1234,
            string:"abcd",
            array:[1,2,3,'abc'],
            map:{one:'abc', two:1, three:"abc"}};

function go(){
        $("#button1").click(test);
}

function test(){
        $.ajax({url:"cgi?mod=echo&func=me",
                type:'POST',
                data:JSON.stringify(data),
                success:function(str){
                        var ret = JSON.parse(str);
                        $("#result").html("<pre>"+
                                          JSON.stringify(ret, undefined, 4) +
                                          "</pre>");
                }});
}
</script>

  

总结:模仿《Erlang程序设计(第二版)》上第25.4节“用cowboy构建嵌入式Web服务器”的内容,但书里的代码有一些已经过时了,在网上查了很多资料,也加深了自己对cowboy的理解。这个项目等于是更新了书里的echo服务器。希望能对大家有所帮助。


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值