连接到erlang.org的erlang gen_tcp声称有404

时间:2017-11-19 02:39:51

标签: erlang httpclient erlang-ports

上下文:JA"编程Erlang" 2ed,第16章关于文件,第256页,使用解析来自二进制文件的URL的示例。

建议的步骤(在编写scavenge_urls模块的代码之后)是:

B = socket_examples:nano_get_url("www.erlang.org"),
L = scavenge_urls:bin2urls(B),
scavenge_urls:urls2htmlFile(L,"gathered.html").

这失败了(巧妙地) - 列表L最终为空。单独运行第一步,观察到一个奇怪的事情 - 它确实返回二进制文件,但它不是我想要的二进制文件:

9> B.
<<"HTTP/1.1 404 Not Found\r\nServer: nginx\r\nDate: Sun, 19 Nov 2017 01:57:07 GMT\r\nContent-Type: text/html; charset=UTF-8\r\n"...>>
 shows that this is where the problem lies.

然而在浏览器中对母舰的所有好处!我能够通过替换对socket_examples:nano_get_urls / 1的调用来完成练习,首先使用CURLing替换相同的url,将其转储到文件中,然后将文件:read_file / 1。接下来的步骤都很顺利。

在socket_examples模块中偷看,我看到了:

nano_get_url(Host) ->
    {ok,Socket} = gen_tcp:connect(Host,80,[binary, {packet, 0}]), %% (1)
    ok = gen_tcp:send(Socket, "GET / HTTP/1.0\r\n\r\n"),  %% (2)
    receive_data(Socket, []).

receive_data(Socket, SoFar) ->
    receive
        {tcp,Socket,Bin} ->    %% (3)
            receive_data(Socket, [Bin|SoFar]);
        {tcp_closed,Socket} -> %% (4)
            list_to_binary(reverse(SoFar)) %% (5)
    end.

没有什么看起来可疑。首先它建立连接,然后它触发GET,然后它接收响应。我以前从来没有必须先明确连接,然后激活GET秒,我的http客户端库隐藏了我的内容。所以也许我不知道该找什么......我相信Joe的代码没有任何明显的错误! =)然而,带有注释(3),(4)和(5)的行不是我完全理解的。

那么,任何想法,同事Erlangers? 谢天谢地!

1 个答案:

答案 0 :(得分:4)

问题不在于Erlang。看起来运行erlang.org的服务器也需要Host标头:

$ nc www.erlang.org 80
GET / HTTP/1.0

HTTP/1.1 404 Not Found
Server: nginx
Date: Sun, 19 Nov 2017 05:51:39 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 162
Connection: close
Vary: Accept-Encoding

<html>
<head><title>404 Not Found</title></head>
<body bgcolor="white">
<center><h1>404 Not Found</h1></center>
<hr><center>nginx</center>
</body>
</html>
$ nc www.erlang.org 80
GET / HTTP/1.0
Host: www.erlang.org

HTTP/1.1 200 OK
Server: nginx
Date: Sun, 19 Nov 2017 05:51:50 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 12728
Connection: close
Vary: Accept-Encoding

<!DOCTYPE html>
<html>
...

您的Erlang代码也适用于GET HTTP/1.0\r\n之后的主机标头:

1> Host = "www.erlang.org".
"www.erlang.org"
2> {ok, Socket} = gen_tcp:connect(Host, 80, [binary, {packet, 0}]).
{ok,#Port<0.469>}
3> ok = gen_tcp:send(Socket, "GET / HTTP/1.0\r\nHost: www.erlang.org\r\n\r\n").
ok
4> flush().
Shell got {tcp,#Port<0.469>,
               <<"HTTP/1.1 200 OK\r\nServer: nginx\r\n...>>
Shell got {tcp_closed,#Port<0.469>}