zoukankan      html  css  js  c++  java
  • goweb- 对请求的处理

    对请求的处理

    Go 语言的 net/http 包提供了一系列用于表示 HTTP 报文的结构,我们可以使用它
    处理请求和发送相应,其中 Request 结构代表了客户端发送的请求报文,下面让我们看
    一下 Request 结构体

    获取请求 URL

    Request 结构中的 URL 字段用于表示请求行中包含的 URL,改字段是一个指向
    url.URL 结构的指针

    Path 字段

    注: 通过 r.URL.Path 只能得到 /hello

    RawQuery 字段

    注: 通过 r.URL.RawQuery 得到的是 username=admin&password=123456

    获取请求头中的信息

    通过 Request 结果中的 Header 字段用来获取请求头中的所有信息,Header 字段
    的类型是 Header 类型,而 Header 类型是一个 map[string][]string,string 类型的 key,
    string 切片类型的值。

    获取请求头中的所有信息

    • r.Header

    • 得到的结果如下:

    map[User-Agent:[Mozilla/5.0 (Windows NT 10.0; Win64; x64)
    AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36]
    Accept:[text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,ima
    ge/apng,*/*;q=0.8] Accept-Encoding:[gzip, deflate, br] Accept-Language:[zh-
    CN,zh;q=0.9,en-US;q=0.8,en;q=0.7] Connection:[keep-alive] Upgrade-Insecure-
    Requests:[1]]
    

    获取请求头中的某个具体属性的值,如获取 Accept-Encoding 的值

    • 方式一:r.Header[“Accept-Encoding”]

      • 得到的是一个字符串切片
      • 结果[gzip, deflate, br]
    • 方式二:r.Header.Get(“Accept-Encoding”)

      • 得到的是字符串形式的值,多个值使用逗号分隔
      • 结果 gzip, deflate, br

    获取请求体中的信息

    请求和响应的主体都是有 Request 结构中的 Body 字段表示,这个字段的类型是
    io.ReadCloser 接口,该接口包含了 Reader 接口和 Closer 接口,Reader 接口拥有 Read
    方法,Closer 接口拥有 Close 方法

    通过指定 method=”post”来发送一个 POST 请求

    由于 GET 请求没有请求体,所以我们需要在 HTML 页面中创建一个 form 表单,通
    过指定 method=”post”来发送一个 POST 请求

    • 表单
    <html>
      <head>
        <meta charset="UTF-8" />
      </head>
      <body>
        <form
          action="http://localhost:8080/getBody"
          method="POST"
          enctype="multipart/form-data"
        >
          用户名:<input type="text" name="username" /><br />
          密码:<input type="password" name="password" /><br />
          <input type="submit" />
        </form>
      </body>
    </html>
    
    • 服务器处理请求的代码
    package main
    import (
    "fmt"
    "net/http"
    )
    func handler(w http.ResponseWriter, r *http.Request) {
    //获取内容的长度
    length := r.ContentLength
    //创建一个字节切片
    body := make([]byte, length)
    //读取请求体
    r.Body.Read(body)
    fmt.Fprintln(w, "请求体中的内容是:", string(body))
    }
    func main() {
    http.HandleFunc("/getBody", handler)
    http.ListenAndServe(":8080", nil)
    }
    
    • 在浏览器上显示的结果

      • 请求体中的内容是: username=hanzong&password=666666

    获取请求参数

    下面我们就通过 net/http 库中的 Request 结构的字段以及方法获取请求 URL 后面
    的请求参数以及 form 表单中提交的请求参数

    Form 字段

    1. 类型是 url.Values 类型,Form 是解析好的表单数据,包括 URL 字段的 query
      参数和 POST 或 PUT 的表单数据。
    2. Form 字段只有在调用 Request 的 ParseForm 方法后才有效。在客户端,会忽
      略请求中的本字段而使用 Body 替代
    3. 获取表单中提交的请求参数(username 和 password)
    • 代码
    func handler(w http.ResponseWriter, r *http.Request) {
    //解析表单
    r.ParseForm()
    //获取请求参数
    fmt.Fprintln(w, "请求参数为:", r.Form)
    }
    //注意:在执行 r.Form 之前一定要调用 ParseForm 方法
    //结果
    //请求参数为: map[password:[666666] username:[hanzong]]
    
    • d) 如果对 form 表单做一些修改,在 action 属性的 URL 后面也添加相同的请求参
      数,如下:
    <form
      action="http://localhost:8080/getBody?username=admin&pwd=123456"
      method="POST"
    >
      用 户 名 : <input type="text" name="username" value="hanzong" /><br />
      密 码 : <input type="password" name="password" value="666666" /><br />
      <input type="submit" />
    </form>
    

    则执行结果如下:

    请求参数为:map[username:[hanzong admin] password:[666666] pwd:[123456]]

    • 我们发现:表单中的请求参数 username 和 URL 中的请求参数
      username 都获取到了,而且表单中的请求参数的值排在 URL 请求参
      数值的前面
    • 如果此时我们只想获取表单中的请求参数该怎么办呢?那就需要使
      用 Request 结构中的 PostForm 字段

    PostForm 字段

    1. 类型也是 url.Values 类型,用来获取表单中的请求参数
    • 将 r.Form 改为 r.PostForm 之后的代码
    func handler(w http.ResponseWriter, r *http.Request) {
    //解析表单
    r.ParseForm()
    //获取请求参数
    fmt.Fprintln(w, "请求参数为:", r.PostForm)
    }
    
    • 结果

    请求参数为:map[username:[hanzong] password:[666666]]

    1. 但是 PostForm 字段只支持 application/x-www-form-urlencoded 编码,如果
      form 表单的 enctype 属性值为 multipart/form-data,那么使用 PostForm 字段
      无法获取表单中的数据,此时需要使用 MultipartForm 字段
    • 说明:form 表单的 enctype 属性的默认值是 application/x-www-form-
      urlencoded 编 码 , 实 现 上 传 文 件 时 需 要 讲 该 属 性 的 值 设 置 为
      multipart/form-data 编码格式

    FormValue 方法和 e PostFormValue 方法

    FormValue 方法

    a) 可以通过 FormValue 方法快速地获取某一个请求参数,该方法调用之前
    会自动调用 ParseMultipartForm 和 ParseForm 方法对表单进行解析

    • 代码
    func handler(w http.ResponseWriter, r *http.Request) {
    //获取请求参数
    fmt.Fprintln(w, "请求参数username的值为:", r.FormValue("username"))
    }
    
    
    • 结果

    请求参数 username 的值为: hanzong

    PostFormValue 方法

    a) 可以通过 PostFormValue 方法快速地获取表单中的某一个请求参数,该
    方法调用之前会自动调用 ParseMultipartForm 和 ParseForm 方法对表单
    进行解析

    • 代码
    func handler(w http.ResponseWriter, r *http.Request) {
    //获取请求参数
    fmt.Fprintln(w, "请求参数 username 的值为:", r.PostFormValue("username"))
    }
    
    • 结果

    请求参数 username 的值为: hanzong

    MultipartForm 字段

    为了取得 multipart/form-data 编码的表单数据,我们需要用到 Request 结构的
    ParseMultipartForm 方法和 MultipartForm 字段,我们通常上传文件时会将 form 表单的
    enctype 属性值设置为 multipart/form-data

    1. 表单
    <form
      action="http://localhost:8080/upload"
      method="POST"
      enctype="multipart/form-data"
    >
      用 户 名 : <input type="text" name="username" value="hanzong" /><br />
      文件:<input type="file" name="photo" /><br />
      <input type="submit" />
    </form>
    
    1. 后台处理请求代码
    package main
    import (
    "fmt"
    "net/http"
    )
    func handler(w http.ResponseWriter, r *http.Request) {
    //解析表单
    r.ParseMultipartForm(1024)
    
    fmt.Fprintln(w, r.MultipartForm)
    }
    func main() {
    http.HandleFunc("/upload", handler)
    http.ListenAndServe(":8080", nil)
    }
    
    1. 浏览器显示结果

    &{map[username:[hanzong]] map[photo:[0xc042126000]]}

    • 结果中有两个映射,第一个映射映射的是用户名;第二个映射的值是一个地址

    • MuiltipartForm 字段的类型为 *multipart.Form,multipart 包下 Form 结构的指
      针类型

    • 打开上传的文件

    func handler(w http.ResponseWriter, r *http.Request) {
    //解析表单
    r.ParseMultipartForm(1024)
    fileHeader := r.MultipartForm.File["photo"][0]
    file, err := fileHeader.Open()
    if err == nil {
    data, err := ioutil.ReadAll(file)
    if err == nil {
    fmt.Fprintln(w, string(data))
    }
    }
    }
    

    FormFile 方法

    • net/http 提供的 FormFile 方法可以快速的获取被上传的文件,但是只能处理上
      传一个文件的情况。

    • 代码

    func handler(w http.ResponseWriter, r *http.Request) {
    file, _, err := r.FormFile("photo")
    if err == nil {
    data, err := ioutil.ReadAll(file)
    
    if err == nil {
    fmt.Fprintln(w, string(data))
    }
    }
    }
    

    给客户端响应

    前面我们一直说的是如何使用处理器中的 *http.Request 处理用户的请求,下面我
    们来说一下如何使用 http.ResponseWriter 来给用户响应

    给客户端响应一个字符串

    • 处理器中的代码
    func handler(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("你的请求我已经收到"))
    }
    
    • 浏览器中的结果
      你的请求我已经收到
    • 响应报文中的内容
     HTTP/1.1 200 OK
     Date: Fri, 10 Aug 2019 01:09:27 GMT
     Content-Length: 27
     Content-Type: text/plain; charset=utf-8
    
    
    1. 给客户端响应一个 HTML 页面
    2. 处理器中的代码
       func handler(w http.ResponseWriter, r *http.Request) {
       html := `<html>
       <head>
       <title>测试响应内容为网页</title>
       <meta charset="utf-8"/>
       </head>
       <body>
       我是以网页的形式响应过来的!
       </body>
       </html>`
       w.Write([]byte(html))
       }
    
    
    1. 浏览器中的结果
      我是以网页的形式响应过来的!
    • 通过在浏览器中右键 → 查看网页代码发现确实是一个 html 页面
    1. 响应报文中的内容
       HTTP/1.1 200 OK
       Date: Fri, 10 Aug 2018 01:26:58 GMT
       Content-Length: 194
       Content-Type: text/html; charset=utf-8
    
    
    1. 给客户端响应 JSON 格式的数据

    2. 处理器端代码

       func handler(w http.ResponseWriter, r *http.Request) {
       //设置响应头中内容的类型
       w.Header().Set("Content-Type", "application/json")
       user := User{
       ID: 1,
       Username: "admin",
       Password: "123456",
       }
       //将 user 转换为 json 格式
       json, \_ := json.Marshal(user)
       w.Write(json)
       }
    
    
    1. 浏览器中的结果
      {"ID":1,"Username":"admin","Password":"123456"}
    2. 响应报文中的内容
       HTTP/1.1 200 OK
       Content-Type: application/json
       Date: Fri, 10 Aug 2018 01:58:02 GMT
       Content-Length: 47
    
    
    1. 让客户端重定向

    2. 处理器端代码

       func handler(w http.ResponseWriter, r *http.Request) {
       //以下操作必须要在 WriteHeader 之前进行
       w.Header().Set("Location", "https:www.baidu.com")
       w.WriteHeader(302)
       }
    
    
    1. 响应报文中的内容
        HTTP/1.1 302 Found
        Location: https:www.baidu.com
        Date: Fri, 10 Aug 2018 01:45:04 GMT
        Content-Length: 0
        Content-Type: text/plain; charset=utf-8
    
  • 相关阅读:
    H5版俄罗斯方块(5)---需求演进和产品迭代
    vim 常用 NERDTree 快捷键
    C和C++中include 搜索路径的一般形式以及gcc搜索头文件的路径
    MySQL复制协议
    深入解析MySQL replication协议
    Install CodeBlocks in CentOS 7
    Impala 源码分析-FE
    Elasticsearch 6.x 的分页查询数据
    1、树莓派3B开箱+安装系统
    Python创建ES索引
  • 原文地址:https://www.cnblogs.com/ygjzs/p/12052005.html
Copyright © 2011-2022 走看看