标准库中的net/http包提供了多种创建HTTP服务器的方法,它还提供了一个基本路由器。
package main
import "net/http"
func helloWorld(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello World\n")) //[]byte声明一个字节切片并将字符串转换为字节。
}
func main() {
//使用方法HandFunc创建路由/,这个方法接受一个模式和一个函数,前者描述了路径,后者指定如何对发送到该路径的请求做出相应。
http.HandleFunc("/", helloWorld)
//为了相应客户端,使用方法ListenAndServe启动一个服务器,监听localhost和端口8000
http.ListenAndServe(":8000", nil)
}
HandFunc创建了一个路由表,让HTTP服务器能够正确的做出响应。值的注意的是:
路由器默认将没有指定处理程序的请求定向到/。 路由器必须完全匹配,因此/us/最后的斜杠是必须要有的,如果没有,访问http://localhost:8000/us/ 将被定向到/。 路由器不关心请求的类型,而只管将与路由匹配的请求传递给相应的处理程序。
运行结果,命令行内容一直没出来,在“http://localhost:8000/” 网页上出现一句话:“Hello World”。
使用方法HandleFunc创建路由。这个方法接受一个模式和一个函数,其中前者描述了路径,而后者指定如何对发送到该路径的请求做出响应。
为响应客户端,使用方法ListenAndServe来启动一个服务器,这个服务器监听localhost和端口8000.
查看请求和响应
http.HandleFunc("/", helloWorld)
http.HandleFunc("/us/", helloWorld1)
路由器负责将路由映射到函数,但如何处理请求以及如何向客户端返回响应,是由处理程序函数定义的。处理程序函数通常先完成对请求的所有处理,再将响应返回给客户端。
启动Web浏览器,并访问http://localhost:8000/ 便可访问到。也可以不使用浏览器,使用curl来向Web服务器发送各种请求以及查看相应。
curl -is http://localhost:8000
//-is 指定打印报头
默认路由器的行为是将所有没有指定处理程序的请求都定向到/,但我们希望其返回404错误(页面未找到),因此需要在默认路由的函数中添加检查路径。
func helloWorld(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/" {
http.NotFound(w, r)
return
}
w.Write([]byte("Hello World\n"))
}
创建HTTP服务器时,需要设置响应的报头,告诉客户端一些信息。假设服务器将发送一些JSON数据,通过设置Content-Type报头,可以达到这一目的。
w.Header().Set("Content-Type", "application/json; charset=utf-8")
如果服务器支持多种类型的内容,客户端可使用Accept报头请求特定类型的内容,这意味着同一个URL可能向浏览器提供HTML,而向API客户端提供JSON。
func helloWorld(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/" {
http.NotFound(w, r)
return
}
switch r.Header.Get("Accept") {
case "application/json":
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.Write([]byte(`{"message": "World"}`))
case "application/xml":
w.Header().Set("Content-Type", "application/xml; charset=utf-8")
w.Write([]byte(`<?xml version="1.0" encoding="utf-8"?><Message>Hello</Message>`))
default:
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.Write([]byte(`{"hello": "World"}`))
}
}
通过curl向这个Web服务器发送请求,设置不同的类型。
curl -si -H 'Accept: application/json' http://localhost:8000
curl -si -H 'Accept: application/xml' http://localhost:8000
除了响应不同类型的内容外,HTTP服务器也需要能够响应不同类型的请求。HTTP规范中定义了四种请求包括GET/POST/PUT/DELETE。
func helloWorld(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/" {
http.NotFound(w, r)
return
}
switch r.Method {
case "GET":
w.Write([]byte(`{"message": "World"}`))
case "POST":
w.Write([]byte(`{"hello": "WoSSSrld"}`))
default:
//如果请求方法不是GET或POST,就发送501响应,意味着服务器不明白或不支持客户端使用的HTTP请求方法。
w.WriteHeader(http.StatusNotImplemented)
w.Write([]byte(http.StatusText(http.StatusNotImplemented)))
}
}
使用curl向该服务器发送GET和POST请求。
curl -si -X GET http://localhost:8000
curl -si -X POST http://localhost:8000
获取客户端请求中的数据很简单,但获取方式随请求类型而异。对于GET请求,其中的数据通常是通过查询字符串设置的。在POST请求中,数据通常是在请求体中发送的。
func helloWorld(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/" {
http.NotFound(w, r)
return
}
switch r.Method {
case "GET":
for k, v := range r.URL.Query(){
fmt.Println("%s: %s\n", k, v)
}
case "POST":
reqBody, err := ioutil.ReadAll(r.Body)
if err != nil{
log.Fatal(err)
}
fmt.Println("%s\n", reqBody)
default:
//如果请求方法不是GET或POST,就发送501响应,意味着服务器不明白或不支持客户端使用的HTTP请求方法。
w.WriteHeader(http.StatusNotImplemented)
w.Write([]byte(http.StatusText(http.StatusNotImplemented)))
}
}