Go Web开发四:处理请求

1.HTTP报文结构

HTTP分为请求和响应类型,都具有相同的结构:
1.请求行或者响应行
2.0个或者多个首部
3.一个空行
4.一个可选的报文主体

1.1Request结构

Request结构表示一个客户端发送的HTTP请求报文,该结构包含了报文经过语法分析后较为重要的信息。

组成:
1.URL字段
2.Header字段
3.Body字段
4.Form字段
5.PostForm字段
6.MultipartForm字段

通过该结构,可以对请求报文中的cookie,url代理等进行访问。

1.1.1URL字段

表示请求中包含的URL,该字段是一个指向url.URL结构的指针。定义如下:

type URL struct {
    Scheme     string
    Opaque     string    // encoded opaque data
    User       *Userinfo // username and password information
    Host       string    // host or host:port
    Path       string    // path (relative paths may omit leading slash)
    RawPath    string    // encoded path hint (see EscapedPath method)
    ForceQuery bool      // append a query ('?') even if RawQuery is empty
    RawQuery   string    // encoded query values, without '?'
    Fragment   string    // fragment for references, without '#'
}

1.1.2Header字段

请求和响应的首部都使用Header类型描述。

package main

import (
    "net/http"
    "fmt"
)

func main() {
    server := http.Server{
        Addr: "127.0.0.1:8080",
    }
    http.HandleFunc("/headers", headers)
    server.ListenAndServe()
}

func headers(w http.ResponseWriter, r *http.Request) {
    h := r.Header
    fmt.Fprintln(w, h)
}

代码中的r.Header即把请求首部读取出来,并写入response返回给客户端。

可以使用指定键获得Header中的值,如:

//获得字符串切片
h := r.Header["Accept-Encoding"]
//获得字符串,使用逗号分隔开
h := r.Header.Get("Accept-Encoding")

1.1.3Body字段

请求和响应的主体都由Request结构的Body字段表示,该字段是一个io.ReadCloser接口。

使用Read方法读取主体的内容:

func main() {
    server := http.Server{
        Addr: "localhost:8080",
    }
    http.HandleFunc("/body", body)
    server.ListenAndServe()
}

func body(w http.ResponseWriter, r *http.Request) {
    len := r.ContentLength//获取主体数据的字节长度
    body := make([]byte, len)//根据长度创建出字节数组
    r.Body.Read(body)//将主体数据读取到body中
    fmt.Fprintln(w, string(body))
}

在终端使用cURL命令即可模拟POST请求

yuhua$ curl -id "body" localhost:8080/body

输出如下内容:

HTTP/1.1 200 OK
Date: Mon, 25 Jun 2018 15:12:11 GMT
Content-Length: 5
Content-Type: text/plain; charset=utf-8

body

1.1.4Form字段

通过调用Request提供的方法,用户可以将URL,主体等数据提取到Form,PostForm,MultipartForm等字段中。下面代码调用了ParseForm方法,访问时,就应该访问相应的Form字段。

func main() {
    server := http.Server{
        Addr: "localhost:8080",
    }
    http.HandleFunc("/process", process)
    server.ListenAndServe()
}

func process(w http.ResponseWriter, r *http.Request) {
    r.ParseForm()//对表单进行分析
    fmt.Fprintln(w, r.Form)
}

编写好html文件,用浏览器打开:

<html>
<head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
    <title>GoWeb</title>
</head>
<form action=http://127.0.0.1:8080/process?hello=world&thread=123 method="post" enctype="application/x-www-form-urlencoded">
    <input type="text" name="hello" value="sau"/>
    <input type="text" name="post" value="456"/>
    <input type="submit">
</form>
</html>

点击提交后,得到如下结果:

map[post:[456] hello:[sau world] thread:[123]]

我们发现,使用application/x-www-form-urlencoded格式,最终的Form字段会包含URL与body中的值。

2.ResponseWrite

ResponseWrite是一个接口,处理器通过该接口创建HTTP响应。

该接口有3个方法:
1.Write
2.WriteHeader
3.Header

2.1Write

package main

import "net/http"

func main() {
    server := http.Server{
        Addr: "localhost:8080",
    }
    http.HandleFunc("/write", write)
    server.ListenAndServe()
}

func write(w http.ResponseWriter, r *http.Request) {
    str := `<html><head><title>Go Web</title></head><body><h1>Hello World</h1></body></html>`
    w.Write([]byte(str))
}

浏览器浏览后:


屏幕快照 2018-06-26 下午9.23.24.png

2.2WriteHeader

将状态码写入返回中。如:你定义一个API,但是没有实现,当客户端访问时,可以返回501。

package main

import (
    "net/http"
    "fmt"
)

func main() {
    server := http.Server{
        Addr: "localhost:8080",
    }
    http.HandleFunc("/write", write)
    http.HandleFunc("/writeHeader", writeHeader)
    server.ListenAndServe()
}

func write(w http.ResponseWriter, r *http.Request) {
    str := `<html><head><title>Go Web</title></head><body><h1>Hello World</h1></body></html>`
    w.Write([]byte(str))
}

func writeHeader(w http.ResponseWriter, r *http.Request) {
    w.WriteHeader(501)//该方法只允许设置一次,不允许多次设置
    fmt.Fprintln(w, "没有实现!")
}

访问后:


屏幕快照 2018-06-26 下午9.29.30.png

2.3Header

调用Header方法,可以取得一个由首部组成的映射,修改该映射就可以修改首部,修改后的首部被包含在HTTP响应里,并随着响应一同发送至客户端。

package main

import (
    "net/http"
    "fmt"
)

func main() {
    server := http.Server{
        Addr: "localhost:8080",
    }
    http.HandleFunc("/write", write)
    http.HandleFunc("/writeHeader", writeHeader)
    http.HandleFunc("/header", header)
    server.ListenAndServe()
}

func write(w http.ResponseWriter, r *http.Request) {
    str := `<html><head><title>Go Web</title></head><body><h1>Hello World</h1></body></html>`
    w.Write([]byte(str))
}

func writeHeader(w http.ResponseWriter, r *http.Request) {
    w.WriteHeader(501)
    fmt.Fprintln(w, "没有实现!")
}

func header(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Location", "http://www.baidu.com")
    w.WriteHeader(302)
}

浏览器打开会自动跳转到百度页面。

2.4返回JSON

返回Back结构体JSON。

package main

import (
    "net/http"
    "fmt"
    json2 "encoding/json"
)

func main() {
    server := http.Server{
        Addr: "localhost:8080",
    }
    http.HandleFunc("/write", write)
    http.HandleFunc("/writeHeader", writeHeader)
    http.HandleFunc("/header", header)
    http.HandleFunc("/json", jsonBack)
    server.ListenAndServe()
}

func write(w http.ResponseWriter, r *http.Request) {
    str := `<html><head><title>Go Web</title></head><body><h1>Hello World</h1></body></html>`
    w.Write([]byte(str))
}

func writeHeader(w http.ResponseWriter, r *http.Request) {
    w.WriteHeader(501)
    fmt.Fprintln(w, "没有实现!")
}

func header(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Location", "http://www.baidu.com")
    w.WriteHeader(302)
}

type back struct {
    User string
    Threads []string
}

func jsonBack(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Conten-Type", "application/json")
    back := &back{
        User: "Sau",
        Threads: []string{"first", "second", "third"},
    }
    json, _ :=  json2.Marshal(back)
    w.Write(json)
}

浏览器浏览后返回:


屏幕快照 2018-06-26 下午9.43.11.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,080评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,422评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,630评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,554评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,662评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,856评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,014评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,752评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,212评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,541评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,687评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,347评论 4 331
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,973评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,777评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,006评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,406评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,576评论 2 349

推荐阅读更多精彩内容