> For the complete documentation index, see [llms.txt](https://wskdsgcf.gitbook.io/mastering-go-zh-cn/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://wskdsgcf.gitbook.io/mastering-go-zh-cn/12.0/12.7.md).

# 12.7 Go实现web服务器

Go 允许您使用它的标准库函数自己实现一个 web 服务器。在这本书中您第一次看到一个用 Go 实现的 web 服务器应用程序是在[第10章](https://github.com/hantmac/Mastering_Go_ZH_CN/tree/master/eBook/chapter10/10.0.md)，Go 并发-进阶讨论，我们讨论 `context` 包的时候。

> *尽管用 Go 实现的 web 服务器能做需要高效安全的事情，但如果您真正需要一个强大的 web 服务器，支持模块，多站点和虚拟主机的话，您最好使用如 **Apache** 或 **Nginx** 这样的 web 服务器*

这个例子程序命名为 `www.go`，由五部分展示。它的第一部分包含期望的 `import` 声明：

```go
package main

import (
    "fmt"
    "net/http"
    "os"
    "time"
)
```

对于 web 服务器不需要操作 `time` 包。然而，由于服务器要发送时间和日期给客户端，所以这个例子里需要它。

`www.go` 的第二段代码如下：

```go
func myHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Serving: %s\n", r.URL.Path)
    fmt.Printf("Served: %s\n", r.Host)
}
```

这是该程序的第一个处理函数的实现。一个**处理函数**取决于使用的配置可以服务一个或多个 URL。

`www.go` 的第三部分包含如下代码：

```go
func timeHandler(w http.ResponseWriter, r *http.Request) {
    t := time.Now().Format(time.RFC1123)
    Body := "The current time is:"
    fmt.Fprintf(w, "<h1 align=\"center\">%s</h1>", Body)
    fmt.Fprintf(w, "<h2 align=\"center\">%s</h2>\n", t)
    fmt.Fprintf(w, "Serving: %s\n", r.URL.Path)
    fmt.Fprintf(w, "Served time for: %s\n", r.Host)
}
```

 从上面这段 Go 代码，您能看到该程序的第二个处理函数的实现。该函数输出动态内容。

我们的 web 服务器代码的第四部分处理命令行参数和定义支持的 URL：

```go
func main() {
    PORT := ":8001"
    arguments := os.Args
    if len(arguments) == 1 {
        fmt.Println("Using default port number: ", PORT)
    }else{
        PORT = ":" + arguments[1]
    }
    http.HandleFunc("/time", timeHandler)
    http.HandleFunc("/", myHandler)
```

`http.HandleFunc()` 函数把一个URL和一个处理函数关联起来。

`www.go` 程序的最后一段如下：

```go
    err := http.ListenAndServe(PORT, nil)
    if err != nil {
        fmt.Println(err)
        return
    }
}
```

您将在 `http.ListenAndServe()` 函数的帮助下使用期望的端口号启动 web 服务器。

执行 `www.go` 并连接 web 服务器将生成如下输出：

```shell
$ go run www.go
Using default port number: :8001
Served: localhost:8001
Served: localhost:8001
Served time for: localhost:8001
Served: localhost:8001
Served time for: localhost:8001
Served: localhost:8001
Served time for: localhost:8001
Served: localhost:8001
Served: localhost:8001
Served: localhost:8001
```

尽管这个程序的输出提供了一些方便的信息，但我想您更愿意用您喜欢的浏览器看到真正的输出。下面的截图显示了我们的 web 服务器的 `myhandler()` 函数的输出，显示在 **Google Chrome:**

下面的截图显示 `www.go` 也能生成动态页面。在这个例子，它是注册在 `/time` 下的 web 页面，显示当前时间和日期：

这里真正有趣的是除了 `/time` 所有的 URL 都由 `myHandler()` 函数处理，因为它是 `/` 的第一个参数，匹配所有没有与另一个 handler 匹配的 URL。
