获取URL

对于很多现代应用来说,访问互联网上的信息和访问本地文件系统一样重要。Go 语言在 net 这个强大 package 的帮助下提供了一系列的 package 来做这件事情,使用这些包可以更简单地用网络收发信息,还可以建立更底层的网络连接,编写服务器程序。在这些情景下,Go 语言原生的并发特性(在第八章中会介绍)显得尤其好用。

为了最简单地展示基于 HTTP 获取信息的方式,下面给出一个示例程序 fetch ,这个程序将获取对应的 url ,并将其源文本打印出来;这个例子的灵感来源于 curl 工具(译注:unix 下的一个用来发 http 请求的工具,具体可以 man curl )。当然,curl 提供的功能更为复杂丰富,这里只编写最简单的样例。这个样例之后还会多次被用到。

ch1/fetch
Unresolved include directive in modules/ROOT/pages/ch1/ch1-05.adoc - include::example$/ch1/fetch/main.go[]

这个程序从两个 package 中导入了函数,net/httpio/ioutil 包,http.Get 函数是创建 HTTP 请求的函数,如果获取过程没有出错,那么会在 resp 这个结构体中得到访问的请求结果。respBody 字段包括一个可读的服务器响应流。 ioutil.ReadAll 函数从 response 中读取到全部内容;将其结果保存在变量 b 中。resp.Body.Close 关闭 respBody 流,防止资源泄露,Printf 函数会将结果 b 写出到标准输出流中。

$ go build gopl.io/ch1/fetch
$ ./fetch http://gopl.io
<html>
<head>
<title>The Go Programming Language</title>title>
...

HTTP 请求如果失败了的话,会得到下面这样的结果:

$ ./fetch http://bad.gopl.io
fetch: Get http://bad.gopl.io: dial tcp: lookup bad.gopl.io: no such host

译注:在大天朝的网络环境下很容易重现这种错误,下面是 Windows 下运行得到的错误信息:

$ go run main.go http://gopl.io
fetch: Get http://gopl.io: dial tcp: lookup gopl.io: getaddrinfow: No such host is known.

无论哪种失败原因,我们的程序都用了 os.Exit 函数来终止进程,并且返回一个 status 错误码,其值为 1


练习 1.7: 函数调用 io.Copy(dst, src) 会从 src 中读取内容,并将读到的结果写入到 dst 中,使用这个函数替代掉例子中的 ioutil.ReadAll 来拷贝响应结构体到 os.Stdout ,避免申请一个缓冲区(例子中的 b )来存储。记得处理 io.Copy 返回结果中的错误。

练习 1.8: 修改 fetch 这个范例,如果输入的 url 参数没有 http:// 前缀的话,为这个 url 加上该前缀。你可能会用到 strings.HasPrefix 这个函数。

练习 1.9: 修改 fetch 打印出 HTTP 协议的状态码,可以从 resp.Status 变量得到该状态码。

ch1/exercise
Unresolved include directive in modules/ROOT/pages/ch1/ch1-05.adoc - include::example$/ch1/exercise/main.go[]