1. 响应不同类型的内容
在向客户端返回响应时,服务器应根据客户端的具体需求,为其提供不同类型的内容。一些常见的内容类型包括:
- text/plain —— 纯文本格式
- text/html —— HTML格式
- application/json —— JSON格式
- application/xml —— XML格式
服务器通过查询请求头的"Accept"字段,获悉客户端期望接受的内容类型,并返回相应类型的数据内容。
- switch r.Header.Get("Accept") { // r是指 *http.Request
- case "application/json":
- w.Header().Set("Content-Type", "application/json; charset=utf-8")
- w.Write([]byte(`{"Greeting": "Hello World!"}`))
- case "application/xml":
- w.Header().Set("Content-Type", "application/xml; charset=utf-8")
- w.Write([]byte(`<?xml version="1.0" encoding="utf-8"?>
- <Greeting>Hello World!</Greeting>`))
- default: // 如何客户端请求的内容类型服务器无法满足时,我们可以以缺省的方式,以纯文本形式返回
- w.Header().Set("Content-Type", "text/plain; charset=utf-8")
- w.Write([]byte("Hello World!"))
- }
// 响应不同的内容
// 服务器根据请求报头中的Accept字段,向客户机发送与其要求类型一致的数据
//
// 通过curl发起HTTP请求,可执行如下命令:
// 通过curl向服务器发起请求,可使用-H选项设置请求头中的特定字段
// curl -is -H "Accept: application/json" "http://localhost:8000"
// curl -is -H "Accept: application/xml" "http://localhost:8000"
// curl -is -H "Accept: dummy/dummy" "http://localhost:8000"
package main
import "net/http"
func rootHandler(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(`{"Greeting": "Hello World!"}`))
case "application/xml":
w.Header().Set("Content-Type", "application/xml; charset=utf-8")
w.Write([]byte(`<?xml version="1.0" encoding="utf-8"?><Greeting>Hello World!</Greeting>`))
default:
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
w.Write([]byte("Hello World!"))
}
}
func main() {
http.HandleFunc("/", rootHandler)
http.ListenAndServe(":8000", nil)
}
通过curl向服务器发起请求,可使用-H选项设置请求头中的特定字段。
2. 响应不同类型的请求
为了获知来自客户端的请求类型,可以访问Request中的Method,并通过switch语句针对不同类型的请求,执行不同的操作,例如:
- switch r.Method { // r是指 *http.Request
- case "GET":
- w.Write([]byte("Receive a GET request: Hello World!"))
- case "POST":
- w.Write([]byte("Receive a POST request: Hello World!"))
- default:
- w.WriteHeader(http.StatusNotImplemented) // 对于无法出路的请求,以StatusNotImplemented予以响应
- w.Write([]byte(http.StatusText(http.StatusNotImplemented)))
- }
HTTP协议中的GET请求一般用于从服务器获取数据,而POST请求则意在向服务器提交要被处理的数据,返回的响应里面含有被获取到或处理过的数据。
// 响应不同类型的请求
// 在路由处理函数中,借助switch语句,根据HTTP请求的不同类型,做出不同处理
//
// 通过curl发起HTTP请求,可执行如下命令:
// 通过curl向服务器发起请求,可使用-X选项设置请求的类型
// curl -is -X GET "http://localhost:8000"
// curl -is -X POST "http://localhost:8000"
// curl -is -X DUMMY "http://localhost:8000"
package main
import "net/http"
func rootHandler(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/" {
http.NotFound(w, r)
return
}
switch r.Method {
case "GET":
w.Write([]byte("Receive a GET request: Hello World!"))
case "POST":
w.Write([]byte("Receive a POST request: Hello World!"))
default:
w.WriteHeader(http.StatusNotImplemented)
w.Write([]byte(http.StatusText(http.StatusNotImplemented)))
}
}
func main() {
http.HandleFunc("/", rootHandler)
http.ListenAndServe(":8000", nil)
}
通过curl向服务器发起请求,可使用-X选项设置请求的类型。
3. 获取请求数据
对于GET请求,其携带的数据通常就位于查询字符串中。
- http://localhost:8000/?username=yanan&password=123456
- 对于这样的数据,可通过调用Request.URL.Query()方法获得。
- for k, v := range r.URL.Query() { ... }
- 请求中的每个数据项均被视为一个键值对,等号左边为键(k),右边为值(v)
对于POST请求,数据通常放在请求体中。
- 对于这样的数据,可通过读取Request.Body获得
- reqBody, err := ioutil.ReadAll(r.Body)
- 这样得到的请求数据是一个字节切片,其内部格式需要自行解析。
注意所有进入服务器的数据都应被视为是不安全的,需经过滤后再使用。
// 处理请求中的数据
// GET请求的数据通常以查询字符串的形式跟URL连
// 在一起,而POST请求的数据则位于请求报文体中
//
// 通过curl发起HTTP请求,可执行如下命令:
// curl -is -X GET "http://localhost:8000/?username=yanan&password=123456"
// curl -is -X POST -d "some data to send" "http://localhost:8000"
package main
import (
"fmt"
"io/ioutil"
"log"
"net/http"
)
func rootHandler(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.Printf("%v: %v\n", k, v)
}
w.Write([]byte("Receive a GET request: Hello World!"))
case "POST":
reqBody, err := ioutil.ReadAll(r.Body)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s\n", reqBody)
w.Write([]byte("Receive a POST request: Hello World!"))
default:
w.WriteHeader(http.StatusNotImplemented)
w.Write([]byte(http.StatusText(http.StatusNotImplemented)))
}
}
func main() {
http.HandleFunc("/", rootHandler)
http.ListenAndServe(":8000", nil)
}
// 用户输入:
GET:username: yanan
password: 123456
POST:some data to send