首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >inets httpd:“用户指南”中的服务器示例不起作用

inets httpd:“用户指南”中的服务器示例不起作用
EN

Stack Overflow用户
提问于 2018-02-25 10:13:59
回答 1查看 525关注 0票数 1

我直接从inets用户指南中复制了代码:

代码语言:javascript
复制
$ erl
Erlang/OTP 19 [erts-8.2] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] 

Eshell V8.2  (abort with ^G)

1> inets:start().
ok

2> {ok, Pid} = inets:start(httpd, [{port, 0}, {server_name,"httpd_test"}, {server_root,"/tmp"}, {document_root,"/tmp/htdocs"}, {bind_address, "localhost"}]).

=ERROR REPORT==== 25-Feb-2018::03:08:14 ===
Failed initiating web server: 
undefined
{invalid_option,{non_existing,{document_root,"/tmp/htdocs"}}}

** exception error: no match of right hand side value 
                    {error,
                        {{shutdown,
                             {failed_to_start_child,
                                 {httpd_manager,{127,0,0,1},60152,default},
                                 {error,
                                     {invalid_option,
                                         {non_existing,{document_root,"/tmp/htdocs"}}}}}},
                         {child,undefined,
                             {httpd_instance_sup,{127,0,0,1},60152,default},
                             {httpd_instance_sup,start_link,
                                 [[{port,60152},
                                   {bind_address,{127,0,0,1}},
                                   {server_name,"httpd_test"},
                                   {server_root,"/tmp"},
                                   {document_root,"/tmp/htdocs"}],
                                  15000,
                                  {<0.73.0>,#Port<0.904>},
                                  []]},
                             permanent,infinity,supervisor,
                             [httpd_instance_sup]}}}
3> 

document_root是一个无效的选项?好的,我将检查有效选项列表并纠正example....hmmmm中的错误,似乎没有错误。

好吧,我需要这么做:

代码语言:javascript
复制
$ cd /tmp
$ mkdir htdocs

现在,我试图绑定到本地主机的ipv6版本,但是我没有运气。httpd文档说:

代码语言:javascript
复制
{bind_address, ip_address() | hostname() | any}

ip_address()定义为:

代码语言:javascript
复制
ip_address() = {N1,N2,N3,N4} % IPv4 | {K1,K2,K3,K4,K5,K6,K7,K8} % IPv6

但N和K没有定义。如果N是整数,什么是K?我试过:

代码语言:javascript
复制
{bind_address, {0,0,0,0,0,0,0,1}}

但我有个错误:

代码语言:javascript
复制
$ erl
Erlang/OTP 19 [erts-8.2] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]

Eshell V8.2  (abort with ^G)

1> inets:start().
ok

2> inets:start(httpd, [{port, 0}, {server_name, "httpd_test"}, {server_root, "."}, {document_root, "./htdocs"}, {bind_address,{0,0,0,0,0,0,0,1}}]).
{error,{listen,{exit,badarg}}}

然而,有了ipv4地址,一切都如预期的那样工作:

代码语言:javascript
复制
3> inets:start(httpd, [{port, 0}, {server_name, "httpd_test"}, {server_root, "."}, {document_root, "./htdocs"}, {bind_address,{127,0,0,1}}]).
{ok,<0.74.0>}

4> httpd:info(pid(0,74,0)).        
[{mime_types,[{"htm","text/html"},{"html","text/html"}]},
 {server_name,"httpd_test"},
 {bind_address,{127,0,0,1}},
 {server_root,"."},
 {port,63069},
 {document_root,"./htdocs"}]

5> httpc:request("http://localhost:63069/file1.txt").
{ok,{{"HTTP/1.1",200,"OK"},
     [{"date","Mon, 26 Feb 2018 03:02:33 GMT"},
      {"etag","nCZT0114"},
      {"server","inets/6.3.4"},
      {"content-length","14"},
      {"content-type","text/plain"},
      {"last-modified","Mon, 26 Feb 2018 02:51:52 GMT"}],
     "Hello, world!\n"}}

/ets/主机:

代码语言:javascript
复制
##
# Host Database
#
# localhost is used to configure the loopback interface
# when the system is booting.  Do not change this entry.
##
127.0.0.1   localhost
255.255.255.255 broadcasthost
::1             localhost 

接下来,我尝试了{bind_address, any}

代码语言:javascript
复制
$ erl
Erlang/OTP 19 [erts-8.2] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]

Eshell V8.2  (abort with ^G)

1> inets:start().
ok

2> {ok, Server} = inets:start(httpd, [{port, 0}, {server_name, "httpd_test"}, {server_root, "."}, {document_root, "./htdocs"}, {bind_address, any}]).
{ok,<0.72.0>}

3> httpd:info(Server).
[{mime_types,[{"htm","text/html"},{"html","text/html"}]},
 {server_name,"httpd_test"},
 {bind_address,any},
 {server_root,"."},
 {port,63679},
 {document_root,"./htdocs"}]

但是,我无法使用ipv6地址执行get请求:

代码语言:javascript
复制
4> httpc:request("http://[::1]:63679/file1.txt").          
{error,{failed_connect,[{to_address,{"::1",63679}},
                        {inet,[inet],nxdomain}]}}

5> httpc:request("http://127.0.0.1:63679/file1.txt").
{ok,{{"HTTP/1.1",200,"OK"},
     [{"date","Mon, 26 Feb 2018 03:13:35 GMT"},
      {"etag","nCZT0114"},
      {"server","inets/6.3.4"},
      {"content-length","14"},
      {"content-type","text/plain"},
      {"last-modified","Mon, 26 Feb 2018 02:51:52 GMT"}],
     "Hello, world!\n"}}

好的,我解决了当我试图将服务器绑定到一个ipv6地址时遇到的错误:我需要指定选项{ipfamily, inet6}

代码语言:javascript
复制
inets:start(httpd, [{port, 0}, 
                    {server_name, "httpd_test"}, 
                    {server_root, "."}, 
                    {document_root, "./htdocs"}, 
                    {ipfamily, inet6}, 
                    {bind_address,{0,0,0,0,0,0,0,1}}]).

但是,我的httpc:request()仍然失败:

代码语言:javascript
复制
4> httpd:info(Server).
[{mime_types,[{"htm","text/html"},{"html","text/html"}]},
 {ipfamily,inet6},  
 {server_name,"httpd_test"},
 {bind_address,{0,0,0,0,0,0,0,1}},
 {server_root,"."},
 {port,51284},
 {document_root,"./htdocs"}]

5> httpc:request("http://[::1]:51284/file1.txt").
{error,{failed_connect,[{to_address,{"::1",52489}},
                        {inet,[inet],nxdomain}]}

我可以使用curl使用ipv6地址发出get请求:

代码语言:javascript
复制
~$ curl -v "http://[::1]:52489/file1.txt"
*   Trying ::1...
* TCP_NODELAY set
* Connected to ::1 (::1) port 52489 (#0)
> GET /file1.txt HTTP/1.1
> Host: [::1]:52489
> User-Agent: curl/7.58.0
> Accept: */*
> 
< HTTP/1.1 200 OK
< Date: Mon, 26 Feb 2018 05:07:07 GMT
< Server: inets/6.3.4
< 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 ::1 left intact

这让我相信httpc:request()在ipv6地址上有问题。

好的,我尝试为ipv6配置客户机:

代码语言:javascript
复制
1> inets:start().
ok

2> {ok, Client} = inets:start(httpc, [{profile, client1_config}] ). 
{ok,<0.72.0>}

3> Client.
<0.72.0>

7> httpc:set_options([{ipfamily, inet6}], client1_config).    
ok

手指祈祷..。

代码语言:javascript
复制
8> httpc:request("http://[::1]:52489/file1.txt", client1_config). 
{error,
    {failed_connect,
        [{to_address,{"::1",52489}},
         {inet6,[inet6],nxdomain}]}}

然后,我尝试了(我为易读性添加的间隔):

代码语言:javascript
复制
9> httpc:request(
         get, 
         "http://[::1]:52489/file1.txt", 
         [], 
         [{ipv6_host_with_brackets, true}], 
         client1_config
   ).
** exception error: no function clause matching httpc:request(get,"http://[::1]:52489/file1.txt",[],
                                                              [{ipv6_host_with_brackets,true}],
                                                              client1_config) (httpc.erl, line 149)

这个错误对我来说毫无意义。有一个httpc:五arg版本 (),我仔细检查了所有arg的类型,我的类型是正确的:

代码语言:javascript
复制
httpc:request(atom, string, list_of_tuples, list_of_tuples, atom)

好的,第二个参数实际上是一个元组:{string, []}。以下是我现在在服务器上的位置:

代码语言:javascript
复制
7> httpd:info(Server).
[{mime_types,[{"htm","text/html"},{"html","text/html"}]},
 {ipfamily,inet6},
 {server_name,"httpd_test"},
 {bind_address,{0,0,0,0,0,0,0,1}},
 {server_root,"."},
 {port,53686},
 {document_root,"./htdocs"}]

客户:

代码语言:javascript
复制
32> httpc:get_options(all, client1_config).
{ok,[{proxy,{undefined,[]}},
     {https_proxy,{undefined,[]}},
     {pipeline_timeout,0},
     {max_pipeline_length,2},
     {max_keep_alive_length,5},
     {keep_alive_timeout,120000},
     {max_sessions,2},
     {cookies,disabled},
     {verbose,verbose},
     {ipfamily,inet6},
     {ip,default},
     {port,default},
     {socket_opts,[]}]}

但我的客户仍然无法连接到ipv6地址。我不知道是否应该使用httpc:request()选项{ipv6_host_with_brackets, true},所以我尝试了两种方法:

代码语言:javascript
复制
34> httpc:request(get, {"http://[::1]:52489/file1.txt", []}, [], [{ipv6_host_with_brackets, true}], client1_config).    
(<0.124.0>) << {dbg,{ok,[{matched,nonode@nohost,1}]}}
(<0.124.0>) << {#Ref<0.0.3.431>,
                {ok,<<16,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0>>}}
(<0.124.0>) << {inet_async,#Port<0.981>,5,{error,econnrefused}}
(<0.124.0>) << {'EXIT',#Port<0.981>,normal}
(<0.124.0>) << {init_error,error_connecting,
                   {#Ref<0.0.3.426>,
                    {error,
                        {failed_connect,
                            [{to_address,{"::1",52489}},
                             {inet6,[inet6],econnrefused}]}}}}
{error,{failed_connect,[{to_address,{"::1",52489}},
                        {inet6,[inet6],econnrefused}]}}

35> httpc:request(get, {"http://[::1]:52489/file1.txt", []}, [], [], client1_config).                               
(<0.126.0>) << {dbg,{ok,[{matched,nonode@nohost,1}]}}
(<0.126.0>) << {#Ref<0.0.3.447>,
                {ok,<<16,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0>>}}
(<0.126.0>) << {inet_async,#Port<0.982>,6,{error,econnrefused}}
(<0.126.0>) << {'EXIT',#Port<0.982>,normal}
(<0.126.0>) << {init_error,error_connecting,
                   {#Ref<0.0.3.442>,
                    {error,
                        {failed_connect,
                            [{to_address,{"::1",52489}},
                             {inet6,[inet6],econnrefused}]}}}}
{error,{failed_connect,[{to_address,{"::1",52489}},
                        {inet6,[inet6],econnrefused}]}}

36> httpc:request(get, {"http://[0:0:0:0:0:0:0:1]:52489/file1.txt", []}, [], [{ipv6_host_with_brackets, true}], client1_config).
(<0.128.0>) << {dbg,{ok,[{matched,nonode@nohost,1}]}}
(<0.128.0>) << {#Ref<0.0.3.463>,
                {ok,<<16,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0>>}}
(<0.128.0>) << {inet_async,#Port<0.983>,7,{error,econnrefused}}
(<0.128.0>) << {'EXIT',#Port<0.983>,normal}
(<0.128.0>) << {init_error,error_connecting,
                   {#Ref<0.0.3.458>,
                    {error,
                        {failed_connect,
                            [{to_address,{"0:0:0:0:0:0:0:1",52489}},
                             {inet6,[inet6],econnrefused}]}}}}
{error,{failed_connect,[{to_address,{"0:0:0:0:0:0:0:1",
                                     52489}},
                        {inet6,[inet6],econnrefused}]}}

37> httpc:request(get, {"http://[0:0:0:0:0:0:0:1]:52489/file1.txt", []}, [], [], client1_config).                       
(<0.130.0>) << {dbg,{ok,[{matched,nonode@nohost,1}]}}
(<0.130.0>) << {#Ref<0.0.3.479>,
                {ok,<<16,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0>>}}
(<0.130.0>) << {inet_async,#Port<0.984>,8,{error,econnrefused}}
(<0.130.0>) << {'EXIT',#Port<0.984>,normal}
(<0.130.0>) << {init_error,error_connecting,
                   {#Ref<0.0.3.474>,
                    {error,
                        {failed_connect,
                            [{to_address,{"0:0:0:0:0:0:0:1",52489}},
                             {inet6,[inet6],econnrefused}]}}}}
{error,{failed_connect,[{to_address,{"0:0:0:0:0:0:0:1",
                                     52489}},
                        {inet6,[inet6],econnrefused}]}}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-02-25 10:45:14

好吧!我得到了一个客户端,可以使用ipv6地址成功地提出请求。对于所有的要求,在我的问题底部,我指定了错误的端口。一旦我获得了与服务器端口匹配的客户端端口,那么所有这些请求都成功了。这是我的装置:

服务器配置:

代码语言:javascript
复制
7> httpd:info(Server).
[{mime_types,[{"htm","text/html"},{"html","text/html"}]},
 {ipfamily,inet6},
 {server_name,"httpd_test"},
 {bind_address,{0,0,0,0,0,0,0,1}},
 {server_root,"."},
 {port,53686},
 {document_root,"./htdocs"}]

8>   

客户端配置:

代码语言:javascript
复制
52> httpc:get_options(all, client1_config).
{ok,[{proxy,{undefined,[]}},
     {https_proxy,{undefined,[]}},
     {pipeline_timeout,0},
     {max_pipeline_length,2},
     {max_keep_alive_length,5},
     {keep_alive_timeout,120000},
     {max_sessions,2},
     {cookies,disabled},
     {verbose,false},
     {ipfamily,inet6},  
     {ip,default},
     {port,default},
     {socket_opts,[]}]}

53> 

以下是请求的最短语法:

代码语言:javascript
复制
53> httpc:request("http://[::1]:53686/file1.txt", client1_config).
{ok,{{"HTTP/1.1",200,"OK"},
     [{"date","Mon, 26 Feb 2018 10:21:39 GMT"},
      {"etag","nCZT0114"},
      {"server","inets/6.3.4"},
      {"content-length","14"},
      {"content-type","text/plain"},
      {"last-modified","Mon, 26 Feb 2018 02:51:52 GMT"}],
     "Hello, world!\n"}}

因此,不需要httpc:request()选项{ipv6_host_with_brackets, true}

当我阅读httpc文档时,配置文件部分并没有向我注册。但是配置文件由客户端的配置选项组成,它也是存储cookie的地方,因此您需要将配置文件包含在后续请求中。

有一个默认的配置文件,当您没有指定自己的配置文件时,我猜它会在每个请求中自动发送,而且我认为默认配置文件将为您处理cookie。(不,不是默认的。我在httpc:set_options()的定义下面找到了以下内容:

CookieMode =已启用的/禁用的\x验证 如果启用cookie,所有有效cookie将自动保存在客户端管理器的cookie数据库中。如果使用了“验证”选项,则必须调用函数store_cookie/2来保存cookies。默认为禁用

还可以将配置选项添加到默认配置文件中。

但是,如果您需要对一些请求使用像ipv6这样的配置,而不是其他请求,那么您可以在httpc: request ()'s和其他请求的默认配置文件中创建一个指定的配置文件,并在需要时使用指定的配置文件。客户端配置选项参见httpc:set_options()。有点困惑的是,httpc:request()有一个选项参数,它允许您指定其他选项(请参阅httpc:request/5下面列出的选项列表)。一些请求选项,比如同步和流,似乎更适合于配置文件:

配置文件跟踪可应用于多个请求的代理选项、cookie和其他选项。 http://erlang.org/doc/man/httpc.html

如果通过调用inets:start(httpc, profile_name)创建配置文件,则返回值是客户端的Pid,它在单独的进程中分离,并在使用该配置文件时处理请求。您可以使用以下任何一种方法杀死客户端:

代码语言:javascript
复制
inets:stop(httpc, name_of_profile)
inets:stop(httpc, ClientPid)
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48972369

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档