
Web编程基础http响应
如何响应客户端的请求。最简单的方式是通过 http.ResponseWriter 发送字符串给客户端。
但是这种方式仅限于发送字符串
1.ResponseWriter
ResponseWriter
func (w http.ResponseWriter, r *http.Request)这里的 ResponseWriter 其实是定义在 net/http 包中的一个接口:
// src/net/http/ type ReponseWriter interface { Header() Header Write([]byte) (int, error) WriteHeader(statusCode int) }我们响应客户端请求都是通过该接口的 3 个方法进行的。例如之前fmt.Fprintln(w,"Hello,Web") 其实底层调用 Write 方法。
收到请求后,多路复用器会自动创建一个 http.response 对象,它实现了 http.ResponseWriter接口,然后将该对象和请求对象作为参数传给处理器。那为什么请求对象使用的是结构指针
*http.Request ,而响应要使用接口呢实际上,请求对象使用指针是为了能在处理逻辑中方便地获取请求信息。而响应使用接口来操作,底层也是对象指针,可以保存修改。
2接口 ResponseWriter 有 3 个方法
ResponseWriter 有 3 个方法:
- Write
- WriteHeader
- Header
3.Write 方法
由于接口 ResponseWriter 拥有方法 Write([]byte) (int, error) ,所以实现了 ResponseWriter接口的结构也实现了 io.Writer 接口
// src/io/io.go type Writer interface { Write(p []byte) (n int, err error) }这也是为什么 http.ResponseWriter 类型的变量 w 能在下面代码中使用的原因( fmt.Fprintln的第一个参数接收一个 io.Writer 接口):
fmt.Fprintln(w, "Hello World")我们也可以直接调用 Write 方法来向响应中写入数据:
func writeHandler(w http.ResponseWriter, r *http.Request) { str := `<html> <head><title>Go Web</title></head> <body><h1>直接使用 Write 方法<h1></body> </html>` w.Write([]byte(str)) } mux.HandleFunc("/write", writeHandler)
如何设置状态码和响应内容的类型呢?这就是 WriteHeader 和 Header() 两个方法的作用。
4.WriteHeader 方法
WriteHeader 方法的名字带有一点误导性,它并不能用于设置响应首部。 WriteHeader 接收一个整数,并将这个整数作为 HTTP 响应的状态码返回。调用这个返回之后,可以继续对 ResponseWriter 进行写入,但是不能对响应的首部进行任何修改操作。如果用户在调用 Write 方法之前没有执行过WriteHeader 方法,那么程序默认会使用 200 作为响应的状态码。
如果,我们定义一个 API,还未定义其实现。那么请求这个 API 时,可以返回一个 501 Not Implemented 作为状态码。
func writeHeaderHandler(w http.ResponseWriter, r *http.Request) { w.WriteHeader(501) fmt.Fprintln(w, "This API not implemented!!!") } mux.HandleFunc("/writeheader", writeHeaderHandler)使用 curl 来测试刚刚编写的处理器
curl -i localhost:8080/writeheader返回
HTTP/1.1 501 Not Implemented Date: Wed, 1 Jan 2020 14:15:16 GMT Content-Length: 28 Content-Type: text/plain; charset=utf-8 This API not implemented!!!
5.Header 方法
Header 方法其实返回的是一个 http.Header 类型,该类型的底层类型为 map[string][]string :
// src/net/http/header.go type Header map[string][]string类型 Header 定义了CRUD 方法,可以通过这些方法操作首部。
func headerHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Location", "http://baidu.com") w.WriteHeader(302) }通过第一篇文章我们知道 302 表示重定向,浏览器收到该状态码时会再发起一个请求到首部中Location 指向的地址。使用 curl 测试:
curl -i localhost:8080/header返回
HTTP/1.1 302 Found Location: http://baidu.com Date: Wed, 1 Jan 2020 14:17:49 GMT Content-Length: 0如何在浏览器中打开 localhost:8080/header ,网页会重定向到百度首页
接下来,我们看如何设置自定义的内容类型。通过 Header.Set 方法设置响应的首部 Contet-Type即可。我们编写一个返回 JSON 数据的处理器:
type User struct { FirstName string `json:"first_name"` LastName string `json:"last_name"` Age int `json:"age"` Hobbies []string `json:"hobbies"` } func jsonHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") u := &User { FirstName: "ls", LastName: "ls", Age: 18, Hobbies: []string{"reading", "learning"}, } data, _ := json.Marshal(u) w.Write(data) } mux.HandleFunc("/json", jsonHandler)通过 curl 发送请求:
curl -i localhost:8080/json返回:
HTTP/1.1 200 OK Content-Type: application/json Date: Wed, 1 Jan 2020 14:31:03 GMT Content-Length: 78 {"first_name":"ls","last_name":"ds","age":18,"hobbies":["reading","learning"]}可以看到响应首部中类型 Content-Type 被设置成了 application/json 。类似的格式还有xml( application/xml ) /pdf( application/pdf ) /png( image/png )等等