Background
- 有一堆数据需要用Golang来处理,数据是使用Erlang的term_to_binary保存的。
- 数据是热数据,因此不能一次性对数据进行binary_to_term预处理。
- Erlang的Ports是不太合适的,因为Ports的设计更侧重于Erlang主动与外部进程(一般是其他语言编写的)进行通信。
- 基于通用协议使得Golang与Erlang直接可以通信是唯一的出路,通用协议如http, thrift, protobuf等都可以,因此这条出路还挺宽。BERT-RPC强大而笨重,但是没有Golang的RPC Client. 由于需求非常简单,考虑基于Erlang httpd写一个简单的Web Server完成这个任务。
如果不是Erlang, 这个任务应该是分分钟搞定,但是Erlang的官方文档缺乏example, 相关的文章又太少。难怪有人会吐槽:
When I first started using Erlang it took a fair bit of trial and error to create a server that generated dynamic HTTP content. The main problem is the lack of good tutorials out there for doing these kinds of things. The documentation that comes with Erlang is good for reference, but is not that helpful if you’re just learning the language.
How
下面是将用户输入的内容返回给用户的echo server代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
%% -*- codeing: utf-8 -*- -module(echo_server). -author('liudanking@gmail.com'). -export([start/0, echo/3]). start() -> inets:stop(), application:ensure_started(inets), inets:start(httpd, [ {modules,[mod_esi]}, {port, 8080}, {server_name, "localhost"}, {document_root, "."}, {server_root, "."}, {erl_script_alias, {"/esi", [echo_server]}} ]). echo(SessionID, _Env, Input) -> io:format("~p~n", [Input]), Header = ["Content-Type: text/plain; charset=utf-8\r\n\r\n"], Content = "echo返回:", mod_esi:deliver(SessionID, [Header, unicode:characters_to_binary(Content), Input]). |
- httpd实现了一套处理http request的behavior, 通过配置可以设置如何路由这些请求。这里使用esi的方式来处理请求。erl_script_alias依赖mod_esi. 因此{modules,[mod_esi]}不能省去。上例将/esi/echoserver:func交给echo_server:func处理。因此,可以通过 http://localhost:8080/esi/echo_server:echo?abcd你好321 进行测试。
- httpd定义了一堆mod_*来处理请求,modules之间的顺序有限制的,启用多个模块需要注意。
- mod_esi:deliver()第一段内容必须设置Header:
Use this callback function to dynamically generate dynamic web content. When a part of the page is generated send the data back to the client through deliver/2. Note that the first chunk of data sent to the client must at least contain all HTTP header fields that the response will generate. If the first chunk does not contain the End of HTTP header, that is “\r\n\r\n”, the server will assume that no HTTP header fields will be generated.
- 如果返回的内容有unicode字符,需要使用unicode模块处理,否则浏览器会乱码。