HTTP 是目前互联网上最常用的协议,不仅仅应用于访问网页,现在一些内部服务也开始使用 HTTP,例如 gPRC 等等。
其实 HTTP 协议的内部结构非常简单,我尝试写了一个最简单的 HTTP 客户端,功能只有:
- 从 DNS 获取到域名对应的 ip
- 向 ip 发送一个 tcp 消息,内容是一个 HTTP GET 请求的字符串
- 返回收到的回复
因为没有解析 header 的功能,所以只能根据时间来判断回复是否已经结束 :P。
defmodule M7 do
@data """
GET / HTTP/1.0\r\n
"""
def test(domain) do
ip = getip(domain)
{:ok, socket} = :gen_tcp.connect(ip, 80, [:binary, {:active, true}])
:gen_tcp.send(socket, @data)
loop_receive()
end
def getip(url) do
{:ok, {:hostent, _, _, :inet, _, ips}} =
String.to_charlist(url)
|> :inet_res.gethostbyname()
hd(ips)
end
defp loop_receive() do
Stream.repeatedly(fn ->
receive do
{:tcp, _port, data} ->
{:ok, data}
after
1000 ->
{:error, :timeout}
end
end)
|> Enum.reduce_while([], fn
{:ok, data}, acc ->
{:cont, [data | acc]}
{:error, _}, acc ->
{:halt, Enum.reverse(acc)}
end)
|> IO.iodata_to_binary()
end
end
尝试几个著名网站,发现只有 google 会正常返回网页的内容。apple 会按 HTTP/1.0
协议返回 400。其它的网站不是不返回任何东西,就是以 HTTP/1.1
返回一个错误信息。
我觉得可能是一些网站不支持 HTTP/1.0
,也可能是它们发现我的请求里没有附带一些必要的 Header 所以拒绝服务。
觉得有趣就点个赞?吧~ 周一到周五每天更新。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。