好的,我的工作正常了。首先,当我四处寻找时,我偶然发现:
10 个 Erlang 开发者必备的 Erlang 工具
其中是我迄今为止使用过的最伟大的 erlang“工具”:
退出 erlang shell 时不会清除的命令历史记录。
您可以按照此处的说明安装/启用它: https ://github.com/ferd/erlang-history
回到手头的问题:
1)我发现httpd模块的顺序很重要。 mod_esi
需要在之前mod_get
:
服务器配置文件:
[
{modules, [
mod_alias,
mod_actions,
mod_esi,
mod_cgi,
mod_get,
mod_log
]},
{bind_address, "localhost"},
{port,0},
{server_name,"httpd_test"},
{server_root,"/Users/7stud/erlang_programs/inets_proj"},
{document_root,"./htdocs"},
{script_alias, {"/cgi-bin/", "/Users/7stud/erlang_programs/inets_proj/cgi-bin/"} },
{erl_script_alias, {"/erl", [mymod]} },
{erl_script_nocache, true},
{error_log, "./errors.log"},
{transfer_log, "./requests.log"}
].
正确获取模块顺序后,由于奇怪的转换路径,我不再收到“找不到文件”错误。
2) esi 模块的代码必须在server_root
目录中。我的 esi 模块的名称是mymod.erl
:
~/erlang_programs$ tree inets_proj/
inets_proj/
├── cgi-bin
│ ├── 1.pl
│ ├── example
│ │ ├── httpd_example.beam
│ │ └── httpd_example.erl
│ ├── httpd_example.beam
│ └── httpd_example.erl
├── cl.beam
├── cl.erl
├── errors.log
├── htdocs
│ └── file1.txt
├── mylog.log
├── mymod.beam
├── mymod.erl
├── requests.log
├── s.beam
├── s.erl
├── server.conf
├── xhttpd_example.beam
└── xhttpd_example.erl
3)因为我指定:
{erl_script_alias, {"/erl", [mymod]} }
我需要使用的网址是:
http://localhost:57867/erl/mymod:get_data
端口必须与服务器的端口匹配。正确的路径是您在 erl_script_alias 属性中指定的任何路径加上/modulename:funcname
或/modulename/funcname
。
这是 mymod.erl:
-module(mymod).
-export([get_data/3]).
log(Data) ->
{ok, IoDevice} = file:open(
"/Users/7stud/erlang_programs/inets_proj/mylog.log",
[append]
),
file:write(IoDevice, Data),
file:close(IoDevice).
get_data(SessionID, Env, Input) ->
Headers = "Content-Type: text/html\r\n\r\n",
Data = [
<<"Hello, ">>,
"esi!\n"
],
log(io_lib:format(
"Inside mymod:get_data()\nSessionId=~p\nEnv=~p\nInput=~p\n",
[SessionID, Env, Input]
)),
mod_esi:deliver(SessionID, Headers), %Headers must be a string.
mod_esi:deliver(SessionID, Data). %Data can be an iolist.
根据mod_esi 文档:
mod_esi:deliver/2用于生成对客户端的响应,SessionID 是一个标识符,在调用此函数时应使用,不要假设任何有关数据类型的信息。可以多次调用此函数来分块响应数据。请注意,发送到客户端的第一个数据块必须至少包含响应将生成的所有 HTTP 标头字段。如果第一个块不包含 HTTP 标头的结尾,即“\r\n\r\n”,则服务器假定不会生成 HTTP 标头字段。
4)编译mymod.erl:
~/erlang_programs/inets_proj$ erlc mymod.erl
~/erlang_programs/inets_proj$
每次更改 mymod.erl 后都必须重新编译,然后重新启动服务器。如果这可行,那就更简单了:
5> httpd:reload_config("server.conf", disturbing).
{error,{missing_property,server_name}}
但即使我的配置文件确实指定了 server_name 属性,我也会收到该错误。
5)我建议您通过包含mod_log
在模块列表中并指定属性来进行错误记录:
{error_log, "./errors.log"}
然后检查该文件以获取有关请求失败时发生的情况的任何反馈。
6)当我调用我的自定义 log() 方法(以便将一些信息写入文件)时,我不知道 log() 方法导致异常,导致服务器拒绝请求并module traverse failed
错误输入消息。日志:
[Timestamp], module traverse failed: mod_esi:do =>
Error Type: exit
Error: {mod_esi_linked_process_died,<0.97.0>,normal}
Stack trace: [{mod_esi,receive_headers,1,[{file,"mod_esi.erl"},{line,428}]},
{mod_esi,deliver_webpage_chunk,3,
[{file,"mod_esi.erl"},{line,389}]},
{mod_esi,erl_scheme_webpage_chunk,5,
[{file,"mod_esi.erl"},{line,380}]},
{mod_esi,generate_webpage,7,
[{file,"mod_esi.erl"},{line,314}]},
{httpd_response,traverse_modules,2,
[{file,"httpd_response.erl"},{line,77}]},
{httpd_response,generate_and_send_response,1,
[{file,"httpd_response.erl"},{line,44}]},
{httpd_request_handler,handle_response,1,
[{file,"httpd_request_handler.erl"},{line,655}]},
{gen_server,try_dispatch,4,
[{file,"gen_server.erl"},{line,616}]}]
7)这是我用来启动服务器的模块:
-module(s).
-compile(export_all).
%Need to look up port with httpd:info(Server)
ensure_inets_start() ->
case inets:start() of
ok -> ok;
{error,{already_started,inets}} -> ok
end.
start() ->
ok = s:ensure_inets_start(),
{ok, Server} = inets:start(httpd,
[{proplist_file, "./server.conf"}]
),
Server.
stop(Server) ->
ok = inets:stop(httpd, Server).
8) 以下是一些使用 curl 的示例请求...
shell中的服务器信息:
~/erlang_programs/inets_proj$ erl
Erlang/OTP 20 [erts-9.2] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V9.2 (abort with ^G)
1> c(s).
s.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,s}
2> S = s:start().
<0.86.0>
3> httpd:info(S).
[{mime_types,[{"htm","text/html"},{"html","text/html"}]},
{server_name,"httpd_test"},
{erl_script_nocache,true},
{script_alias,{"/cgi-bin/",
"/Users/7stud/erlang_programs/inets_proj/cgi-bin/"}},
{bind_address,{127,0,0,1}},
{modules,[mod_alias,mod_actions,mod_esi,mod_cgi,mod_get,
mod_log]},
{server_root,"/Users/7stud/erlang_programs/inets_proj"},
{erl_script_alias,{"/erl",[mymod]}},
{port,59202},
{transfer_log,<0.93.0>},
{error_log,<0.92.0>},
{document_root,"./htdocs"}]
4>
请求 1(esi 获取请求):
~$ curl -v "http://localhost:57867/erl/mymod:get_data"
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 57867 (#0)
> GET /erl/mymod:get_data HTTP/1.1
> Host: localhost:57867
> User-Agent: curl/7.58.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Wed, 28 Feb 2018 13:28:09 GMT
< Server: inets/6.4.5
< Cache-Control: no-cache
< Pragma: no-cache
< Expires: Wed, 28 Feb 2018 13:28:09 GMT
< Transfer-Encoding: chunked
< Content-Type: text/html
<
Hello, esi!
* Connection #0 to host localhost left intact
~$
mylog.log:
~/erlang_programs/inets_proj$ cat mylog.log
...
...
Inside mymod:get_data()
SessionId=<0.99.0>
Env=[{server_software,"inets/6.4.5"},
{server_name,"httpd_test"},
{host_name,"ChristophersMBP"},
{gateway_interface,"CGI/1.1"},
{server_protocol,"HTTP/1.1"},
{server_port,59202},
{request_method,"GET"},
{remote_addr,"127.0.0.1"},
{peer_cert,undefined},
{script_name,"/erl/mymod:get_data"},
{http_host,"localhost:59202"},
{http_user_agent,"curl/7.58.0"},
{http_accept,"*/*"}]
Input=[]
-------
请求 2(esi 获取带有查询字符串的请求):
~$ curl -v "http://localhost:59202/erl/mymod:get_data?a=1&b=2"
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 59202 (#0)
> GET /erl/mymod:get_data?a=1&b=2 HTTP/1.1
> Host: localhost:59202
> User-Agent: curl/7.58.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Wed, 28 Feb 2018 13:47:41 GMT
< Server: inets/6.4.5
< Cache-Control: no-cache
< Pragma: no-cache
< Expires: Wed, 28 Feb 2018 13:47:41 GMT
< Transfer-Encoding: chunked
< Content-Type: text/html
<
Hello, esi!
* Connection #0 to host localhost left intact
mylog.log:
~/erlang_programs/inets_proj$ cat mylog.log
...
...
Inside mymod:get_data()
SessionId=<0.105.0>
Env=[{server_software,"inets/6.4.5"},
{server_name,"httpd_test"},
{host_name,"ChristophersMBP"},
{gateway_interface,"CGI/1.1"},
{server_protocol,"HTTP/1.1"},
{server_port,59202},
{request_method,"GET"},
{remote_addr,"127.0.0.1"},
{peer_cert,undefined},
{script_name,"/erl/mymod:get_data?a=1&b=2"},
{http_host,"localhost:59202"},
{http_user_agent,"curl/7.58.0"},
{http_accept,"*/*"},
{query_string,"a=1&b=2"}]
Input="a=1&b=2"
请求 3(esi 发布请求):
~$ curl -v --data "a=1&b=2" "http://localhost:59202/erl/mymod:get_data"
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 59202 (#0)
> POST /erl/mymod:get_data HTTP/1.1
> Host: localhost:59202
> User-Agent: curl/7.58.0
> Accept: */*
> Content-Length: 7
> Content-Type: application/x-www-form-urlencoded
>
* upload completely sent off: 7 out of 7 bytes
< HTTP/1.1 200 OK
< Date: Wed, 28 Feb 2018 13:51:44 GMT
< Server: inets/6.4.5
< Cache-Control: no-cache
< Pragma: no-cache
< Expires: Wed, 28 Feb 2018 13:51:44 GMT
< Transfer-Encoding: chunked
< Content-Type: text/html
<
Hello, esi!
* Connection #0 to host localhost left intact
mylog.log:
Inside mymod:get_data()
SessionId=<0.108.0>
Env=[{server_software,"inets/6.4.5"},
{server_name,"httpd_test"},
{host_name,"ChristophersMBP"},
{gateway_interface,"CGI/1.1"},
{server_protocol,"HTTP/1.1"},
{server_port,59202},
{request_method,"POST"},
{remote_addr,"127.0.0.1"},
{peer_cert,undefined},
{script_name,"/erl/mymod:get_data"},
{http_host,"localhost:59202"},
{http_user_agent,"curl/7.58.0"},
{http_accept,"*/*"},
{http_content_length,"7"},
{http_content_type,"application/x-www-form-urlencoded"}]
Input="a=1&b=2"
-------
请求 4(cgi 获取请求):
~$ curl -v "http://localhost:59202/cgi-bin/1.pl"
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 59202 (#0)
> GET /cgi-bin/1.pl HTTP/1.1
> Host: localhost:59202
> User-Agent: curl/7.58.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Wed, 28 Feb 2018 13:41:43 GMT
< Server: inets/6.4.5
< Transfer-Encoding: chunked
< Content-Type: text/html
<
Hello, Perl.
* Connection #0 to host localhost left intact
请求 5(从 document_root 目录获取常规文件的请求):
~$ curl -v "http://localhost:59202/file1.txt"
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 59202 (#0)
> GET /file1.txt HTTP/1.1
> Host: localhost:59202
> User-Agent: curl/7.58.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Wed, 28 Feb 2018 13:42:15 GMT
< Server: inets/6.4.5
< Content-Type: text/plain
< Etag: nCZT0114
< Content-Length: 14
< Last-Modified: Mon, 26 Feb 2018 02:51:52 GMT
<
Hello, world!
* Connection #0 to host localhost left intact