目的
net/http

Package http provides HTTP client and server implementations.

监听请求并响应

WebServer本质上来说很简单,主要可以为两步:

  • 监听某个端口号上收到的HTTP数据;
  • 根据收到的HTTP请求中的路径执行对应的操作;

下面是个简单的示例:

package main

import (
	"fmt"
	"log"
	"net/http"
	"time"
)

func hello(w http.ResponseWriter, r *http.Request) { //回调函数,回调函数将在协程中运行
	time.Sleep(4 * time.Second)
	fmt.Fprintf(w, "Hello, you've requested: %s\n", r.URL.Path) // 向客户端应答数据
}

func naisu(w http.ResponseWriter, r *http.Request) { //回调函数
	fmt.Fprintln(w, "Naisu 233!") // 向客户端应答数据
}

func main() {
	http.HandleFunc("/", hello)      // 设置路由地址与对应回调函数
	http.HandleFunc("/naisu", naisu) // 实际应用中通常根据需求设置多个路由地址与对应回调函数

	err := http.ListenAndServe(":80", nil) // 启动WebServer,监听80端口,可以在本机浏览器中通过 http://localhost:<端口号><路由地址> 进行访问(80端口可以省略:80)
	// err := http.ListenAndServe("0.0.0.0:80", nil) // 在本机所有网卡上进行监听,同网段下的设备可以通过 http://本机IP地址/ 进行访问
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}

上面示例中核心涉及的就两个方法:

func HandleFunc(pattern string, handler func(ResponseWriter, *Request))func ListenAndServe(addr string, handler Handler) errorListenAndServeTLS
请求解析
func(http.ResponseWriter, *http.Request)

下面例子中打印了请求对象中的一些内容:

package main

import (
	"fmt"
	"net/http"
)

func hello(w http.ResponseWriter, r *http.Request) {
	fmt.Println(r.Method)
	fmt.Println(r.URL)
	fmt.Println(r.Header) // 请求头,各个请求头字段以字典形式保存
	fmt.Println(r.Body)
	fmt.Println(r.ContentLength)
}

func main() {
	http.HandleFunc("/", hello)

	http.ListenAndServe(":80", nil)
}
/favicon.ico
Request
进行响应

进行响应主要就是设置响应头字段,设置状态码,写正文内容这些。

package main

import (
	"io"
	"net/http"
)

func hello(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Trailer", "AtEnd1, AtEnd2")                 // 设置(添加)响应头字段
	w.Header().Add("Trailer", "AtEnd3")                         // 添加响应头字段
	w.Header().Set("Content-Type", "text/plain; charset=utf-8") // 添加响应头字段
	w.WriteHeader(http.StatusOK)                                // 写状态码
	io.WriteString(w, "Hello Naisu.\n")                         // 响应body内容
	// 注意写头字段、状态码和body的顺序
}

func main() {
	http.HandleFunc("/", hello)

	http.ListenAndServe(":80", nil)
}
ResponseWriter 
静态文件服务
index.html
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
</head>
<body>
    <h1 style="color: #4DD498;">Hello Naisu!</h1>
</body>
</html>

然后使用下面方式启动静态文件服务:

package main

import (
	"net/http"
)

func main() {
	fs := http.FileServer(http.Dir("./"))       // 设置静态文件存放路径,可以使用绝对或相对路径
	http.Handle("/", http.StripPrefix("/", fs)) // 设置静态文件路由处理,通过 http://localhost/文件名 进行访问
	// http.Handle("/static/", http.StripPrefix("/static/", fs)) // 通过 http://localhost/static/文件名 进行访问
	// 设置静态文件存放路径根目录下的 index.html 文件可以不加文件名进行访问

	http.ListenAndServe(":80", nil)
}
func ServeFile(w ResponseWriter, r *Request, name string)
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    http.ServeFile(w, r, "index.html")
})
.
总结
net/http

实际工作中如果需求比较全面的话全部细节功能都从头实现的话就比较麻烦了。Golang有一个非常出名的用于Web开发的工具库Gorilla,实现了很多常用的功能:
https://www.gorillatoolkit.org/

对于更加复杂的项目也可以直接使用现成的框架。Gin是一个Golang的主流的轻量级Web框架,其官网和项目地址如下:
https://gin-gonic.com/
https://github.com/gin-gonic/gin