inets httpd:用户指南中的服务器示例不工作
inets httpd: server example in User's Guide not working
我直接从 inets 用户指南中复制了代码:
$ 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
是无效选项?好的,我会检查有效选项列表并更正示例中的错误....嗯,好像没有。
好的,我需要这样做:
$ cd /tmp
$ mkdir htdocs
现在,我正在尝试绑定到本地主机的 ipv6 版本,但我没有运气。 httpd docs 说:
{bind_address, ip_address() | hostname() | any}
和ip_address()定义为:
ip_address() = {N1,N2,N3,N4} % IPv4 | {K1,K2,K3,K4,K5,K6,K7,K8} % IPv6
但 N 和 K 未定义。如果 N 是整数,那么 K 是多少?我试过了:
{bind_address, {0,0,0,0,0,0,0,1}}
但是我得到一个错误:
$ 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 地址一切正常:
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/hosts:
##
# 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}
:
$ 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 地址执行获取请求:
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}
:
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() 仍然失败:
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请求:
~$ 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 配置客户端:
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
双手合十....
8> httpc:request("http://[::1]:52489/file1.txt", client1_config).
{error,
{failed_connect,
[{to_address,{"::1",52489}},
{inet6,[inet6],nxdomain}]}}
然后我尝试了(我为易读性添加的间距):
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:request()的five arg version,我仔细检查了所有args的类型,我的类型是正确的:
httpc:request(atom, string, list_of_tuples, list_of_tuples, atom)
好吧,第二个参数实际上是一个元组:{string, []}
。这是我现在使用服务器的位置:
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"}]
而客户:
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}
或不,所以我一直在尝试两种方式:
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}]}}
好的!我有一个客户端成功地使用 ipv6 地址发出请求。对于问题底部的所有请求,我指定了错误的端口。一旦我让客户端端口与服务器端口相匹配,那么所有这些请求都会成功。这是我的设置:
服务器配置:
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>
客户端配置:
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>
下面是请求的最短语法:
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 文档时,profile 部分并没有真正向我注册。但是配置文件由客户端的配置选项组成,它也是存储 cookie 的地方,因此您需要将配置文件包含在后续请求中。
有一个默认配置文件,我想当您没有指定自己的配置文件时,它会自动随每个请求一起发送,我认为默认配置文件会为您处理 cookie。 (不,默认情况下不是。我在 httpc:set_options() 的定义下方找到以下内容:
CookieMode = enabled | disabled | verify
If cookies are enabled, all
valid cookies are automatically saved in the cookie database of the
client manager. If option verify is used, function store_cookies/2 has
to be called for the cookies to be saved. Default is disabled.
您还可以将配置选项添加到默认配置文件。
但是如果您需要对某些请求使用像 ipv6 这样的配置而不是其他请求,那么您可以创建一个命名配置文件并在需要时在 httpc:request() 和默认配置文件中使用该命名配置文件其他请求的配置文件(通过不指定命名配置文件)。有关客户端配置选项,请参阅 httpc:set_options()
。有点令人困惑的是,httpc:request() 有一个 Options 参数,它允许您指定其他选项(在 httpc:request/5 定义下方的文档中查看这些选项的列表)。某些请求选项,如同步和流,似乎更适合配置文件:
A profile keeps track of proxy options, cookies, and other options
that can be applied to more than one request.
如果您通过调用 inets:start(httpc, profile_name)
创建一个配置文件,return 值是客户端的 Pid,它在一个单独的进程中分离出来并在使用该配置文件时处理请求。您可以使用以下任一方式终止客户端:
inets:stop(httpc, name_of_profile)
inets:stop(httpc, ClientPid)
我直接从 inets 用户指南中复制了代码:
$ 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
是无效选项?好的,我会检查有效选项列表并更正示例中的错误....嗯,好像没有。
好的,我需要这样做:
$ cd /tmp
$ mkdir htdocs
现在,我正在尝试绑定到本地主机的 ipv6 版本,但我没有运气。 httpd docs 说:
{bind_address, ip_address() | hostname() | any}
和ip_address()定义为:
ip_address() = {N1,N2,N3,N4} % IPv4 | {K1,K2,K3,K4,K5,K6,K7,K8} % IPv6
但 N 和 K 未定义。如果 N 是整数,那么 K 是多少?我试过了:
{bind_address, {0,0,0,0,0,0,0,1}}
但是我得到一个错误:
$ 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 地址一切正常:
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/hosts:
##
# 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}
:
$ 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 地址执行获取请求:
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}
:
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() 仍然失败:
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请求:
~$ 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 配置客户端:
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
双手合十....
8> httpc:request("http://[::1]:52489/file1.txt", client1_config).
{error,
{failed_connect,
[{to_address,{"::1",52489}},
{inet6,[inet6],nxdomain}]}}
然后我尝试了(我为易读性添加的间距):
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:request()的five arg version,我仔细检查了所有args的类型,我的类型是正确的:
httpc:request(atom, string, list_of_tuples, list_of_tuples, atom)
好吧,第二个参数实际上是一个元组:{string, []}
。这是我现在使用服务器的位置:
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"}]
而客户:
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}
或不,所以我一直在尝试两种方式:
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}]}}
好的!我有一个客户端成功地使用 ipv6 地址发出请求。对于问题底部的所有请求,我指定了错误的端口。一旦我让客户端端口与服务器端口相匹配,那么所有这些请求都会成功。这是我的设置:
服务器配置:
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>
客户端配置:
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>
下面是请求的最短语法:
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 文档时,profile 部分并没有真正向我注册。但是配置文件由客户端的配置选项组成,它也是存储 cookie 的地方,因此您需要将配置文件包含在后续请求中。
有一个默认配置文件,我想当您没有指定自己的配置文件时,它会自动随每个请求一起发送,我认为默认配置文件会为您处理 cookie。 (不,默认情况下不是。我在 httpc:set_options() 的定义下方找到以下内容:
CookieMode = enabled | disabled | verify
If cookies are enabled, all valid cookies are automatically saved in the cookie database of the client manager. If option verify is used, function store_cookies/2 has to be called for the cookies to be saved. Default is disabled.
您还可以将配置选项添加到默认配置文件。
但是如果您需要对某些请求使用像 ipv6 这样的配置而不是其他请求,那么您可以创建一个命名配置文件并在需要时在 httpc:request() 和默认配置文件中使用该命名配置文件其他请求的配置文件(通过不指定命名配置文件)。有关客户端配置选项,请参阅 httpc:set_options()
。有点令人困惑的是,httpc:request() 有一个 Options 参数,它允许您指定其他选项(在 httpc:request/5 定义下方的文档中查看这些选项的列表)。某些请求选项,如同步和流,似乎更适合配置文件:
A profile keeps track of proxy options, cookies, and other options that can be applied to more than one request.
如果您通过调用 inets:start(httpc, profile_name)
创建一个配置文件,return 值是客户端的 Pid,它在一个单独的进程中分离出来并在使用该配置文件时处理请求。您可以使用以下任一方式终止客户端:
inets:stop(httpc, name_of_profile)
inets:stop(httpc, ClientPid)