0

上下文:JA 的“Programming 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 的调用来完成练习,首先,对相同的 url 进行 CURL,将其转储到文件中,然后是 file: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 客户端库对我隐藏了这一点。所以也许我不知道要寻找什么……而且我确信乔的代码没有任何明显的错误!=) 然而,带有注释 (3)、(4) 和 (5) 的行并不是我完全理解的。

那么,有什么想法吗,厄兰格兄弟们?谢谢一堆!

4

1 回答 1

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 代码也适用于 Host 标头之后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>}
于 2017-11-19T06:00:03.647 回答