# 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。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://wskdsgcf.gitbook.io/mastering-go-zh-cn/12.0/12.7.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
