18.3 HTTP服务器-响应不同类型的内容和请求、获取请求数据

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值