inets httpd:无法使用简单的esi脚本来工作 [英] inets httpd: Can't get simple esi script to work

查看:113
本文介绍了inets httpd:无法使用简单的esi脚本来工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我用来配置httpd服务器的proplist_file:

Here's the proplist_file that I use to configure the httpd server:

[
  {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脚本,关键属性为:

For esi scripts the key property is:

  {erl_script_alias, {"/cgi-bin/example", [httpd_example]} }

根据 inets文档:

ESI属性-需要mod_esi

{erl_script_alias,{URLPath,[AllowedModule]}}
URLPath = string()和AllowedModule = atom(). erl_script_alias标记所有URL 匹配url-path作为erl方案脚本.匹配的URL被映射到 特定的模块和功能,例如:

{erl_script_alias, {URLPath, [AllowedModule]}}
URLPath = string() and AllowedModule = atom(). erl_script_alias marks all URLs matching url-path as erl scheme scripts. A matching URL is mapped into a specific module and function, for example:

 {erl_script_alias, {"/cgi-bin/example", [httpd_example]}}

http://your.server.org/cgi-bin/example/httpd_example:yahoo将引用 到httpd_example:yahoo/3,或者,如果不存在, httpd_example:yahoo/2和 http://your.server.org/cgi-bin/example/other:yahoo不会 允许执行.

A request to http://your.server.org/cgi-bin/example/httpd_example:yahoo would refer to httpd_example:yahoo/3 or, if that does not exist, httpd_example:yahoo/2 and http://your.server.org/cgi-bin/example/other:yahoo would not be allowed to execute.

我的目录结构是:

~/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_example模块放在哪里,所以我将其放置在几个地方.

I wasn't sure where to put the httpd_example module, so I put it in several places.

esi_mod.erl:

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.

这是外壳程序中报告的服务器信息:

Here is the server info as reported in the 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> 

这是我的要求:

~$ curl -vv "http://localhost:64470/cgi-bin/example/httpd_example:get_data"
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 64470 (#0)
> GET /cgi-bin/example/httpd_example:get_data HTTP/1.1
> Host: localhost:64470
> User-Agent: curl/7.58.0
> Accept: */*
> 
< HTTP/1.1 404 Object Not Found
< Date: Wed, 28 Feb 2018 10:22:38 GMT
< Server: inets/6.4.5
< Content-Type: text/html
< Content-Length: 245
< 
<HTML>
       <HEAD>
           <TITLE>Object Not Found</TITLE>
      </HEAD>
      <BODY>
      <H1>Object Not Found</H1>
The requested URL &#47;cgi-bin&#47;example&#47;httpd_example:get_data was not found on this server.
</BODY>
      </HTML>
* Connection #0 to host localhost left intact
~$ 

errors.log:

errors.log:

[时间戳记]访问 /cgi-bin/example/httpd_example:get_data失败127.0.0.1,原因: "httpd_file:无法打开 ./htdocs/cgi-bin/example/httpd_example:get_data:找不到文件"

[Timestamp] access to /cgi-bin/example/httpd_example:get_data failed for 127.0.0.1, reason: "httpd_file: Can't open ./htdocs/cgi-bin/example/httpd_example:get_data: File not found"

根据错误消息,请求路径:

According to the error message, the request path:

/cgi-bin/example/httpd_example:get_data 

已转换为:

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

表示请求路径已添加到./htdocs.呵呵?

which means the request path was tacked onto ./htdocs. Huh??

推荐答案

好的,我的工作正常了.首先,当我四处搜寻时,偶然发现:

Okay, I got things working. First, while I was searching around I happened across:

10个基本Erlang适用于Erlang开发人员的工具

其中包含我迄今为止使用过的最大的erlang工具":

and therein lies the single greatest erlang "tool" that I've used to date:

退出erlang shell时不会清除的命令历史记录.

Command history that isn't wiped out when you exit the erlang shell.

您可以按照以下说明安装/启用它: https://github.com/ferd/erlang-history

You can install/enable it by following the instructions here: https://github.com/ferd/erlang-history

回到眼前的问题:

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

1) I found that the order of the httpd modules is important. mod_esi needs to be before mod_get:

server.conf:

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"}
].

正确设置模块顺序后,由于转换路径奇怪,我不再出现找不到文件"错误.

After getting the module order correct, I stopped getting the "File not found" errors due to the strange converted paths.

2)esi模块的代码必须在server_root目录中.我的esi模块的名称是mymod.erl:

2) The code for the esi module has to be in the server_root directory. My esi module's name is 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所指定的任何路径.

The port has to match the server's port. The proper path is whatever path you specify in the erl_script_alias property plus /modulename:funcname or /modulename/funcname.

这是mymod.erl:

Here's 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标头字段 生成.

mod_esi:deliver/2 shall be used to generate the response to the client and SessionID is an identifier that shall by used when calling this function, do not assume anything about the datatype. This function may be called several times to chunk the response data. Notice 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 assumes that no HTTP header fields will be generated.

4)编译mymod.erl:

4) Compile mymod.erl:

~/erlang_programs/inets_proj$ erlc mymod.erl 
~/erlang_programs/inets_proj$ 

在对mymod.erl进行每次更改后,您都必须重新编译,然后重新启动服务器.如果可行的话,会更简单:

You have to recompile after every change you make to mymod.erl, then restart the server. It would be simpler if this would work:

5> httpd:reload_config("server.conf", disturbing).
{error,{missing_property,server_name}}

但是,即使我的配置文件确实指定了server_name属性,我仍然收到该错误.

but even though my config file does specify a server_name property I get that error.

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

5) I suggest you do error logging by including mod_log in the list of modules and specifying the property:

{error_log, "./errors.log"}

然后检查该文件,以获取有关请求失败时所发生情况的任何反馈.

Then check that file for any feedback on what happened when a request fails.

6)当我调用我自己不知道的自定义log()方法(以便向文件中写入一些信息)时,log()方法导致异常,这导致服务器拒绝请求并输入module traverse failed error.log中的消息:

6) When I called my custom log() method (in order to write some info to a file) unbeknownst to me the log() method was causing an exception, which caused the server to reject the request and enter a module traverse failed message in 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}]}]

7)这是我用来启动服务器的模块:

7) Here's the module I used to start the server:

-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的示例请求...

8) Here are a few sample requests using curl...

外壳中的服务器信息:

~/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获取请求):

Request 1 (esi get request):

~$  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:

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获取带有查询字符串的请求):

Request 2 (esi get request with query string):

~$  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:

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发布请求):

Request 3 (esi post request):

~$  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:

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获取请求):

Request 4 (cgi get request):

~$  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目录获取对常规文件的请求):

Request 5 (get request for regular file from document_root directory):

~$  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

这篇关于inets httpd:无法使用简单的esi脚本来工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆