Erlang iNet httpd:Can';无法使用简单的esi脚本

Erlang iNet httpd:Can';无法使用简单的esi脚本,erlang,inets,Erlang,Inets,下面是我用来配置httpd服务器的proplist_文件: [ {modules, [ mod_alias, mod_actions, mod_cgi, mod_get, mod_esi, mod_log ]}, {bind_address, "localhost"}, {port,0}, {server_name,"httpd_test"}, {server_root,"/Users/7stud/erlang_progr

下面是我用来配置httpd服务器的proplist_文件:

[
  {modules, [
    mod_alias,
    mod_actions,
    mod_cgi,
    mod_get,
    mod_esi,
    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, {"/cgi-bin/example", [httpd_example]} },
  {erl_script_nocache, true},
  {error_log, "./errors.log"},
  {transfer_log, "./requests.log"}
].
对于esi脚本,密钥属性为:

  {erl_script_alias, {"/cgi-bin/example", [httpd_example]} }
根据报告:

ESI属性-需要mod_ESI

{erl\u脚本\u别名,{URLPath,[AllowedModule]}
URLPath=string()和AllowedModule=atom()。erl_脚本_别名标记所有URL 将url路径匹配为erl方案脚本。匹配的URL映射到 特定模块和功能,例如:

 {erl_script_alias, {"/cgi-bin/example", [httpd_example]}}
请求
http://your.server.org/cgi-bin/example/httpd_example:yahoo
将参考 例如:yahoo/3,或者,如果不存在, httpd_示例:yahoo/2和
http://your.server.org/cgi-bin/example/other:yahoo
将不会被删除 允许执行

我的目录结构是:

~/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
├── httpd_example.beam
├── httpd_example.erl
├── mylog.log
├── requests.log
├── s.beam
├── s.erl
└── server.conf
我不确定将
httpd_示例
模块放在哪里,所以我把它放在了几个地方

esi_mod.erl:

-module(esi_mod).
-compile(export_all).

log(Data) ->
    {ok, IoDevice} = file:open(
        "/Users/7stud/erlang_programs/inets_proj/mylog.log",
        [append]
    ),

    ok = file:write(IoDevice, Data),
    file:close(IoDevice).

get_data(SessionID, _Env, _Input) ->
    Headers = "Content-Type: text/html\r\n\r\n",
    Data = "Hello, esi",

    log(["--Inside esi_mod:get_data() ~n"]),

    ok = mod_esi:deliver(SessionID, Headers),  %Headers must be a string.
    ok = mod_esi:deliver(SessionID, Data).     %Data can be an iolist.
以下是shell中报告的服务器信息:

$ 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_cgi,mod_get,mod_esi,
           mod_log]},
 {server_root,"/Users/7stud/erlang_programs/inets_proj"},
 {erl_script_alias,{"/cgi-bin/example",[httpd_example]}},
 {port,64470},
 {transfer_log,<0.93.0>},
 {error_log,<0.92.0>},
 {document_root,"./htdocs"}]
4> 
~/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> 
已转换为:

./htdocs/cgi-bin/example/httpd_example:get_data

这意味着请求路径被附加到
/htdocs
。嗯???

好吧,我有办法了。首先,当我四处搜索时,我偶然发现:

这就是我迄今为止使用的最伟大的erlang“工具”:

退出erlang shell时未清除的命令历史记录

您可以按照此处的说明安装/启用它:

回到手头的问题:

1) 我发现httpd模块的顺序很重要
mod_esi
必须在
mod_get
之前:

server.conf:

[
  {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\u 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]} }
我需要使用的url是:

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.
~/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}}
但是,即使我的配置文件指定了一个服务器名称属性,我也会得到这个错误

5) 我建议您通过在模块列表中包括
mod_log
并指定属性来记录错误:

{error_log, "./errors.log"}
然后检查该文件,查看请求失败时发生的任何反馈

6) 在我不知道的情况下调用我的自定义log()方法(以便将一些信息写入文件)时,log()方法导致异常,导致服务器拒绝请求并在error.log中输入
模块遍历失败的消息

[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}]}]
8) 下面是一些使用curl的示例请求

shell中的服务器信息:

$ 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_cgi,mod_get,mod_esi,
           mod_log]},
 {server_root,"/Users/7stud/erlang_programs/inets_proj"},
 {erl_script_alias,{"/cgi-bin/example",[httpd_example]}},
 {port,64470},
 {transfer_log,<0.93.0>},
 {error_log,<0.92.0>},
 {document_root,"./htdocs"}]
4> 
~/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> 
~/erlang\u程序/inets\u项目$erl
Erlang/OTP 20[erts-9.2][source][64位][smp:4:4][ds:4:4:10][async threads:10][hipe][kernel poll:false]
Eshell V9.2(使用^G中止)
1> 丙(s)。
s、 erl:2:警告:已启用导出\u所有标志-将导出所有功能
{好的,s}
2> S=S:start()。
3> httpd:信息。
[{mime_类型,[{“htm”,“text/html”},{“html”,“text/html”}]},
{server_name,“httpd_test”},
{erl_script_nocache,true},
{script_别名,{”/cgi-bin/“,
“/Users/7stud/erlang_programs/inets_proj/cgi bin/”},
{bind_地址,{127,0,0,1}},
{模块,[mod_别名,mod_操作,mod_esi,mod_cgi,mod_get,
mod_log]},
{server_root,“/Users/7stud/erlang_programs/inets_proj”},
{erl_脚本_别名,{“/erl”,[mymod]},
{port,59202},
{传输日志,},
{错误日志,},
{document_root,“./htdocs”}]
4> 
请求1(esi get请求):

~$curl-v”http://localhost:57867/erl/mymod:get_data"
*正在尝试127.0.0.1。。。
*TCP_节点集
*已连接到本地主机(127.0.0.1)端口57867(#0)
>GET/erl/mymod:GET_data HTTP/1.1
>主机:本地主机:57867
>用户代理:curl/7.58.0
>接受:*/*
> 
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=[]
-------
~/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"
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"
-------
~/erlang\u程序/inets\u项目$cat mylog.log
...
...
mymod内部:获取_数据()
会话ID=
Env=[{server_software,“inets/6.4.5”},
{server_name,“httpd_test”},
{主机名,“ChristophersMBP”},
{网关接口,“CGI/1.1”},
{server_protocol,“HTTP/1.1”},
{server_port,59202},
{request_方法,“GET”},
{远程地址,“127.0.0.1”},
{对等证书,未定义},
{script_name,“/erl/mymod:get_data”},
{http_host,“localhost:59202”},
{http_user_agent,“curl/7.58.0”},
{http_accept,“*/*”}]
输入=[]
-------
请求2(带查询字符串的esi get请求):

~$curl-v”http://localhost:59202/erl/mymod:get_data?a=1&b=2"
*正在尝试127.0.0.1。。。
*TCP_节点集
*已连接到本地主机(127.0.0.1)端口59202(#0)
>GET/erl/mymod:GET_数据?a=1&b=2http/1.1
>主机:localhost:59202
>用户代理:curl/7.58.0
>接受:*/*
> 
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=[]
-------
~/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"
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"
-------
~/erlang\u程序/inets\u项目$cat mylog.log
...
...
mymod内部:获取_数据()
会话ID=
Env=[{server_software,“inets/6.4.5”},
{server_name,“httpd_test”},
{主机名,“ChristophersMBP”},
{网关接口,“CGI/1.1”},
{server_protocol,“HTTP/1.1”},
{server_port,59202},
{request_方法,“GET”},
{远程添加
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"
-------
~$  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
~$  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