page contents

Golang中gin框架的学习

Golang中gin框架的学习 gin框架中常用方法 gin.H{ } 有这么一行c.JSON(200, gin.H{“message”: “use get method”})   这其中有一个gin.H{ },看样子,这像是一个结构体struct,查看gin框...

attachments-2021-06-kCJUuLgV60dbe1de8b0a8.png

Golang中gin框架的学习

gin框架中常用方法

gin.H{ }

有这么一行c.JSON(200, gin.H{“message”: “use get method”})

  这其中有一个gin.H{ },看样子,这像是一个结构体struct,查看gin框架的源码,声明如下:

  所以,这只是一个map结构,别以为是一个struct

设置http请求方式

gin框架封装了http库,提供了GET、POST、PUT、DELETE、PATCH、HEAD、OPTIONS这些http请求方式。

  使用router.method()来绑定路由

  声明如下:

  其中的METHOD可以是上面的7种方式。使用对应的METHOD访问对应的 url path,返回对应的response。

  但是如果使用不对应的method访问path,就会返回404,比如使用post方法访问localhost:8080/get会返回404

切换输出的格式

router.GET("/get", func(c *gin.Context) {
    c.JSON(200, gin.H{"message": "use get method"})
})

上面的这段代码,就是在用户访问localhost:8080时,c.JSON()返回一个响应,响应中的状态码是200,响应内容是一个JSON格式的字符串。

  那么我们就很容易知道,不同的响应内容格式是通过调用*gin.Context类型变量的不同方法来实现的。

常见响应内容格式

gin框架提供了很多响应内容的格式,常用的方法声明如下:

//返回json格式
func (c *Context) JSON(code int, obj interface{})
 
//返回xml格式
func (c *Context) XML(code int, obj interface{})
 
//返回yaml格式
func (c *Context) YAML(code int, obj interface{})
 
//返回string格式
func (c *Context) String(code int, format string, values ...interface{})
 
//渲染html模板后返回
func (c *Context) HTML(code int, name string, obj interface{})

状态码

注意上面每一个响应中都有一个状态码200。

  这个状态码不仅可以手动指定一个数字,比如200,500,404;也可以使用http包中的状态码,语义化的状态码更好理解;

  下面解释http协议中所有的状态码了。

package http
 
// HTTP status codes as registered with IANA.
// See: http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
const (
    StatusContinue           = 100 // RFC 7231, 6.2.1
    StatusSwitchingProtocols = 101 // RFC 7231, 6.2.2
    StatusProcessing         = 102 // RFC 2518, 10.1
 
    StatusOK                   = 200 // RFC 7231, 6.3.1
    StatusCreated              = 201 // RFC 7231, 6.3.2
    StatusAccepted             = 202 // RFC 7231, 6.3.3
    StatusNonAuthoritativeInfo = 203 // RFC 7231, 6.3.4
    StatusNoContent            = 204 // RFC 7231, 6.3.5
    StatusResetContent         = 205 // RFC 7231, 6.3.6
    StatusPartialContent       = 206 // RFC 7233, 4.1
    StatusMultiStatus          = 207 // RFC 4918, 11.1
    StatusAlreadyReported      = 208 // RFC 5842, 7.1
    StatusIMUsed               = 226 // RFC 3229, 10.4.1
 
    StatusMultipleChoices   = 300 // RFC 7231, 6.4.1
    StatusMovedPermanently  = 301 // RFC 7231, 6.4.2
    StatusFound             = 302 // RFC 7231, 6.4.3
    StatusSeeOther          = 303 // RFC 7231, 6.4.4
    StatusNotModified       = 304 // RFC 7232, 4.1
    StatusUseProxy          = 305 // RFC 7231, 6.4.5
    _                       = 306 // RFC 7231, 6.4.6 (Unused)
    StatusTemporaryRedirect = 307 // RFC 7231, 6.4.7
    StatusPermanentRedirect = 308 // RFC 7538, 3
 
    StatusBadRequest                   = 400 // RFC 7231, 6.5.1
    StatusUnauthorized                 = 401 // RFC 7235, 3.1
    StatusPaymentRequired              = 402 // RFC 7231, 6.5.2
    StatusForbidden                    = 403 // RFC 7231, 6.5.3
    StatusNotFound                     = 404 // RFC 7231, 6.5.4
    StatusMethodNotAllowed             = 405 // RFC 7231, 6.5.5
    StatusNotAcceptable                = 406 // RFC 7231, 6.5.6
    StatusProxyAuthRequired            = 407 // RFC 7235, 3.2
    StatusRequestTimeout               = 408 // RFC 7231, 6.5.7
    StatusConflict                     = 409 // RFC 7231, 6.5.8
    StatusGone                         = 410 // RFC 7231, 6.5.9
    StatusLengthRequired               = 411 // RFC 7231, 6.5.10
    StatusPreconditionFailed           = 412 // RFC 7232, 4.2
    StatusRequestEntityTooLarge        = 413 // RFC 7231, 6.5.11
    StatusRequestURITooLong            = 414 // RFC 7231, 6.5.12
    StatusUnsupportedMediaType         = 415 // RFC 7231, 6.5.13
    StatusRequestedRangeNotSatisfiable = 416 // RFC 7233, 4.4
    StatusExpectationFailed            = 417 // RFC 7231, 6.5.14
    StatusTeapot                       = 418 // RFC 7168, 2.3.3
    StatusUnprocessableEntity          = 422 // RFC 4918, 11.2
    StatusLocked                       = 423 // RFC 4918, 11.3
    StatusFailedDependency             = 424 // RFC 4918, 11.4
    StatusUpgradeRequired              = 426 // RFC 7231, 6.5.15
    StatusPreconditionRequired         = 428 // RFC 6585, 3
    StatusTooManyRequests              = 429 // RFC 6585, 4
    StatusRequestHeaderFieldsTooLarge  = 431 // RFC 6585, 5
    StatusUnavailableForLegalReasons   = 451 // RFC 7725, 3
 
    StatusInternalServerError           = 500 // RFC 7231, 6.6.1
    StatusNotImplemented                = 501 // RFC 7231, 6.6.2
    StatusBadGateway                    = 502 // RFC 7231, 6.6.3
    StatusServiceUnavailable            = 503 // RFC 7231, 6.6.4
    StatusGatewayTimeout                = 504 // RFC 7231, 6.6.5
    StatusHTTPVersionNotSupported       = 505 // RFC 7231, 6.6.6
    StatusVariantAlsoNegotiates         = 506 // RFC 2295, 8.1
    StatusInsufficientStorage           = 507 // RFC 4918, 11.5
    StatusLoopDetected                  = 508 // RFC 5842, 7.2
    StatusNotExtended                   = 510 // RFC 2774, 7
    StatusNetworkAuthenticationRequired = 511 // RFC 6585, 6
    )

比如下面的语句:

router.GET("/json", func(c *gin.Context) {
    c.JSON(http.StatusNotFound, gin.H{"message": "not found"})
    //等价于
    //c.JSON(404, gin.H{"message": "not found"})
})

获取URL中的值与request body中的值

参考:https://blog.csdn.net/weixin_34199335/article/details/86362964

gin的文档,接收从客户端发来的各种参数,有两大类方式:

接收单个参数的方法:

c.Param()
c.Query          // 查询URL中的参数
c.DefaultQuery   // 查询URL中的参数,URL中有值则使用该值,没有值使用设置的默认值    
c.PostForm       // (前端request)消息主体body里的x-www-form-urlencoded 参数
c.DefaultPostForm  //前端传过来的消息主体中的参数,可以设置默认值
c.QueryMap
c.PostFormMap
c.FormFile
c.MultipartForm

其中,

c.Query() 和 c.DefaultQuery()方法 ,查询的是URL中的参数

c.PostForm()和c.DefaultPostForm()方法,查询的是前端传过来的消息主体中的参数

各种绑定方法

c.Bind
c.BindJSON
c.BindXML
c.BindQuery
c.BindYAML
c.ShouldBind
c.ShouldBindJSON
c.ShouldBindXML
c.ShouldBindQuery
c.ShouldBindYAML

获取url中的参数

对于请求 url 查询参数用 c.Query

如下面官方的例子中 ?id=1234&page=1 这个,就是 查询参数(query params)

你会看到这个参数就放在url里的

如果参数不是放在url里的,也可以在body里,比如 body 里的x-www-form-urlencoded 参数,如下面的name=manu&message=this_is_great

对于gin,要使用 name := c.PostForm(“name”) api

关注下 Content-Type 这个字段,表示了body的类型,更多看看这篇文章

四种常见的 POST 提交数据方式://imququ.com/post/four-ways-to-post-data-in-http.html

还有像 c.FormFile,用于处理上传文件的

请求示例

POST /post?id=1234&page=1 HTTP/1.1
Content-Type: application/x-www-form-urlencoded
name=manu&message=this_is_great

代码示例

func main() {
    router := gin.Default()
    router.POST("/post", func(c *gin.Context) {
        id := c.Query("id") // 查询参数
        page := c.DefaultQuery("page", "0")
        name := c.PostForm("name") // (前端request)消息主体 body 里的x-www-form-urlencoded 参数
        message := c.PostForm("message")
        fmt.Printf("id: %s; page: %s; name: %s; message: %s", id, page, name, message)
    })
    router.Run(":8080")
}

结果输出

id: 1234; page: 1; name: manu; message: this_is_great

获取请求中的参数

假如有这么一个请求:

POST   /post/test?id=1234&page=1  HTTP/1.1
请求头:  Content-Type: application/x-www-form-urlencoded
form表单参数:  name=manu&message=this_is_great

gin的实现:

id := c.Query("id") //查询请求URL后面的参数
page := c.DefaultQuery("page", "0") //查询请求URL后面的参数,如果没有填写默认值
name := c.PostForm("name") //从表单中查询参数
/
//POST和PUT主体参数优先于URL查询字符串值。
name := c.Request.FormValue("name") 
//返回POST并放置body参数,URL查询参数被忽略
name := c.Request.PostFormValue("name")
//从表单中查询参数,如果没有填写默认值  
message := c.DefaultPostForm("message", "aa") 

假如gin定义的路由路径为:

router.POST("/post/:uuid", func(c *gin.Context){
    ...
}

则获取uuid的值方法为

uuid := c.Param("uuid") //取得URL中参数

其他:

s, _ := c.Get("current_manager") //从用户上下文读取值      
type User struct{
  ID int
  Name string
  Age int
}
var u User

//从http.Request中读取值到User结构体中,手动确定绑定类型binding.Form

err1 := c.BindWith(&u, binding.Form) 

//从http.Request中读取值到User结构体中,根据请求方法类型和请求内容格式类型自动确定绑定类型

err2 := c.Bind(&u)

从session中读取值

//用户上下文和session生命周期不同,每一次请求会生成一个对应的上下文,一次http请求结束,该次请求的上下文结束,一般来说session(会话)会留存一段时间

//session(会话)中一般保存用户登录状态等信息,context(上下文)主要用于在一次http请求中,在中间件(流)中进行信息传递

user := sessions.Default©.get(“user”)

将请求体绑定到不同的结构体中

ShouldBind(&objA)方法

绑定请求体的常规方法使用c.Request.Body,并且不能多次调用

type formA struct {
  Foo string `json:"foo" xml:"foo" binding:"required"`
}
type formB struct {
  Bar string `json:"bar" xml:"bar" binding:"required"`
}
func SomeHandler(c *gin.Context) {
  objA := formA{}
  objB := formB{}
  // This c.ShouldBind consumes c.Request.Body and it cannot be reused.
  if errA := c.ShouldBind(&objA); errA == nil {
    c.String(http.StatusOK, `the body should be formA`)
  // Always an error is occurred by this because c.Request.Body is EOF now.
  } else if errB := c.ShouldBind(&objB); errB == nil {
    c.String(http.StatusOK, `the body should be formB`)
  } else {
    ...
  }
}

ShouldBindBodyWith(&objA)方法

同样,可以使用c.ShouldBindBodyWith

func SomeHandler(c *gin.Context) {
  objA := formA{}
  objB := formB{}
  // This reads c.Request.Body and stores the result into the context.
  if errA := c.ShouldBindBodyWith(&objA, binding.JSON); errA == nil {
    c.String(http.StatusOK, `the body should be formA`)
  // At this time, it reuses body stored in the context.
  } else if errB := c.ShouldBindBodyWith(&objB, binding.JSON); errB == nil {
    c.String(http.StatusOK, `the body should be formB JSON`)
  // And it can accepts other formats
  } else if errB2 := c.ShouldBindBodyWith(&objB, binding.XML); errB2 == nil {
    c.String(http.StatusOK, `the body should be formB XML`)
  } else {
    ...
  }
}

c.ShouldBindBodyWith 在绑定之前将body存储到上下文中,这对性能有轻微影响,因此如果你要立即调用,则不应使用此方法

此功能仅适用于这些格式 – JSON, XML, MsgPack, ProtoBuf。对于其他格式,Query, Form, FormPost, FormMultipart, 可以被c.ShouldBind()多次调用而不影响性能

获取URL中的路径参数

比如:http://localhost:8080/user/jane/20/beijing/female?id=999&height=170&wigth=100

  上面的这个链接中,可以通过向上面讲的使用/user/:name/:age/:addr/:sex来分别匹配jane、20、beijing、female。

获取URL的所有路径参数

gin框架中如果使用URL传递参数,那么在绑定的时候,是这样的:/user/:name/:age/:addr/:sex

  上面这个path绑定了4个URL参数,分别是name、age、addr、sex

  首先gin.Context对象的Params属性保存着URL中的所有参数:

router.GET("/user/:name/:age/:addr/:sex", func(c *gin.Context) {
    //打印URL中所有参数
    c.JSON(200, fmt.Sprintln(c.Params))
})

如果请求http://localhost:8080/user/jane/20/beijing/female

  得到的输出如下:

"[{name jane} {age 20} {addr beijing} {sex female}]"

注意最后面的那个换行符

获取URL中的指定路径参数

使用gin.Context对象的Param(key)方法获取某一个key的值,方法声明如下:

router.GET("/user/:name/:age/:addr/:sex", func(c *gin.Context) {
    name := c.Param("name") //获取参数的时候,不要写name前面的冒号:
    c.JSON(200, name)
})

访问http://localhost:8080/user/jane/20/beijing/female,输出"jane"

获取URL中请求的参数(GET请求)

获取URL中路径值和获取参数不一样。

  比如:http://localhost:8080/user/jane/20/beijing/female?id=999&height=170&wight=100

  可以使用下面的方法获取请求参数id、height、weight的值。

获取指定参数的值

//返回URL中key的值
func (c *Context) Query(key string) string

使用gin.Context.Query(key string)可以获取指定key的值,

  测试:

router.GET("/user/:name/:age/:addr/:sex", func(c *gin.Context) {
    id := c.Query("id")
    height := c.Query("height")
    weight := c.Query("weight")
    c.JSON(200, gin.H{"id": id, "height": height, "weight": weight})
})

访问http://localhost:8080/user/jane/20/beijing/female?id=999&height=170&wight=100,输出内容如下:

{"height":"170","id":"999","weight":"100"}

获取指定参数的值(带有默认值的接收)

当然,以前写php的时候,如果要想判断是否接收到了某个参数,如果没有接收到,那么就设置一个默认值,最常用的就是三元运算符,比如下面这样:

$id = empty($_POST['id']) ? 0 : $_POST['id'];

gin框架当然也想到了这么一点,gin.Context.DefaultQuery()方法,允许指定接收的参数名,以及没有接收到该参数值时,设置的默认值,声明如下:

func (c *Context) DefaultQuery(key, defaultValue string) string

只有当请求没有携带key,那么此时的默认值就会生效。其他情况,默认值不生效。即使URL中的该key的值为空,那么也不会启用默认值,获取的值就是空。

  注意,这是获取URL中的参数值。 

接收multipart/urlencoded form(POST表单数据)

  和获取URL中的参数很相似:

  GET请求中的参数使用Query(key),DefaultQuery(key,default)来获取

  POST请求中的参数使用PostForm(key),DefaultPostForm(key,default)来获取。

package main
 
import (
    "github.com/gin-gonic/gin"
)
 
func main() {
    router := gin.Default()
    router.POST("/post", func(c *gin.Context) {
        name := c.PostForm("name")
        age := c.PostForm("age")
        sex := c.DefaultPostForm("sex", "male")
        c.JSON(200, gin.H{"name": name, "age": age, "sex": sex})
    })
    router.Run()
 }

获注意要想获取POST方式传递的参数,那么绑定的路由监听方式就必须是router.POST,不能使router.GET。

同时获取URL中的参数和POST的参数

  前提:请求方必须是使用POST方式传递,只不过URL中也包含一部分参数而已。

  同时,服务器端必须使用router.POST方式来接收,不能使用router.GET方式接收,因为router.GET只能接收GET方式传递的数据。

package main
 
import (
    "github.com/gin-gonic/gin"
)
 
func main() {
    router := gin.Default()
    //注意,这里必须使用router.POST
    router.POST("/post", func(c *gin.Context) {
        name := c.PostForm("name")
        age := c.PostForm("age")
        sex := c.DefaultPostForm("sex", "male")
        addr := c.Query("addr")
        hobby := c.DefaultQuery("hobby", "basketball")
        c.JSON(200, gin.H{"name": name, "age": age, "sex": sex, "addr": addr, "hobby": hobby})
    })
    router.Run()
}

请求:localhost:8080/post?addr=beijing&hobby=football

  同时使用post方式传递name=abc&age=21111&sex=female

  那么得到的响应就是如下内容:

将GET或POST函数中的func(c *gin.Context)封装成一个函数作为参数传入

实际在项目开发中,通常将将GET或POST函数中的func(c *gin.Context)封装成一个函数作为参数传入,同时将c.JSON(statuscode, gin.H{key:value, })中的gin.H{}配置成所需要的json格式的数据结构,内容使用自定义的struct类型的数据结构返回,例如:

//main.go
//维度补充信息关联数据库
router.GET("/table/dimension/relate/db", handler.GetDBList)
//package handle
//GetDBList 路由中与db相关的绑定方法,不显示返回内容
func GetDBList(c *gin.Context) {
//通过select语句从数据库中获取需要的数据
    dbList, err := api.GetDB()
    if err != nil {
        fmt.Println("get related db info from data_source error:", err)
        response.StatusOK(c, http.StatusInternalServerError, err.Error(), nil)
        return
    }
//使用map[string]interface{}定义数据结构类型,{"list":dbList}使用从数据库中获取到的数据初始化要response给前端的数据内容
    c.JSON(http.StatusOK, map[string]interface{}{
        "list": dbList,
    })
}
//package api
//GetDB 获取有关数据库的id和数据库名称组成的list
func GetDB() ([]InstanceNameID, error) {
//初始化自定义的InstanceNameID数组,用于存放从数据库中筛选出的数据
    res := []InstanceNameID{}
    conn := databases.GetDBConn()
    err := conn.Table("data_source").
        Select("id, instance_name").
        Where("data_source.is_deleted=0").Scan(&res).Error
    if err != nil {
        return []InstanceNameID{}, err
    }
    return res, err
}
//package api
//InstanceNameID 的数据结构定义, ``中的gorm和json的位置无先后顺序,且gorm的value中尽量带上Column, gorm不要拼错,否则其指定的内容会为空
type InstanceNameID struct {
//自定义的struct中的字段,通常需要在其他包中使用,所以需要将首字母大写,代表是导出字段,在其他包中也可以引用;如果不小心写成小写,则改字段的内容可能为空。
    Name string `gorm:"Column:instance_name" json:"name"`
    ID   int64  `gorm:"Column:id" json:"id"`
}

GET与POST请求

什么是 HTTP?

超文本传输协议(HTTP)的设计目的是保证客户机与服务器之间的通信。

HTTP 的工作方式是客户机与服务器之间的请求-应答协议。

web 浏览器可能是客户端,而计算机上的网络应用程序也可能作为服务器端。

举例:客户端(浏览器)向服务器提交 HTTP 请求;服务器向客户端返回响应。响应包含关于请求的状态信息以及可能被请求的内容。

GET与POST请求

gin框架封装了http库,提供了GET、POST、PUT、DELETE、PATCH、HEAD、OPTIONS这些http请求方式。

  使用router.method()来绑定路由,声明如下:

func (group *RouterGroup) METHOD(relativePath string, handlers ...HandlerFunc) IRouters

两种最常用的 HTTP 方法是:GET 和 POST。

在客户机和服务器之间进行请求-响应时,两种最常被用到的方法是:GET 和 POST。

GET - 从指定的资源请求数据。

POST - 向指定的资源提交要被处理的数据

GET 方法

请注意,查询字符串(名称/值 对)是在 GET 请求的 URL 中发送的,例如下列URL(中?后面的键值对)形式,就需要放在GET方法中:

/test/demo_form.asp?name1=value1&name2=value2

有关 GET 请求的其他一些说明:

  1. GET 请求可被缓存
  2. GET 请求保留在浏览器历史记录中
  3. GET 请求可被收藏为书签
  4. GET 请求不应在处理敏感数据时使用
  5. GET 请求只应当用于取回数据
  6. GET 请求有长度限制

POST 方法

请注意,查询字符串(名称/值 对)是在 POST 请求的 HTTP 消息主体中发送的:

POST /test/demo_form.asp HTTP/1.1

Host: w3schools.com

name1=value1&name2=value2

有关 POST 请求的其他一些解释:

  1. POST 请求不会被缓存
  2. POST 请求不会保留在浏览器历史记录中
  3. POST 不能被收藏为书签
  4. POST 请求对数据长度没有要求

GET与POST对比

摘自:HTTP 方法:GET 对比 POST

gin框架中对url参数的解析

Browser(前端) 发出请求, Server(后端)给出响应。

golang要请求远程网页,可以使用net/http包中提供的http.GET()或者http.POST()方法实现。

query string 参数与body参数

query stirng 路由用连接参数的形式,如key1=value1?key2=value2,这是通过urlencode编码后的。 对于query string,经常出现参数不存在的情况,需要提供默认值。

router.GET("/welcome", func(c *gin.Context) {
        firstname := c.DefaultQuery("firstname", "Guest")
        lastname := c.Query("lastname")
        c.String(http.StatusOK, "Hello %s %s", firstname, lastname)
    })

DefaultQuery是当不存在的时候提供一个默认的参数。

body格式有四种: application/json、application/x-www-form-urlencoded、application/xml、multipart/form-data

c.PostFROM解析的是x-www-form-urlencoded或from-data的参数。

比如,运行下面的代码go run main.go

package main
import (
    "github.com/gin-gonic/gin"
)
func main() {
    
    router := gin.Default()
    router.GET("/table/dimension/relate/field", func(c *gin.Context) {
        db := c.Query("db")
        table := c.DefaultQuery("table", "dimension")
        c.JSON(200, gin.H{"db": db, "table": table})
    })
    router.Run("127.0.0.1:5000")
}

并在浏览器中输入这个URL

将会返回json格式的内容—— {“db”:“dw”,“table”:“dimension”}

net/http中的部分方法解析

ListenAndServe函数

ListenAndServe方法根据addr和handler参数构建了一个Server对象,并调用该对象的ListenAndServe方法进行监听和响应。那么第二个参数Handler的作用是什么呢,为什么通常传nil值?

// ListenAndServe always returns a non-nil error.
func ListenAndServe(addr string, handler Handler) error {
server := &Server{Addr: addr, Handler: handler}
return server.ListenAndServe()
}

Handler的定义如下:

type Handler interface {
ServerHTTP(ResponseWriter, *Request)
}

Handler是一个接口类型,包含了ServerHTTP方法,该方法对客户端的请求(Request对象)进行处理,并通过ResponseWriter将响应信息传送回客户端。所以,Handler是Server对象处理请求的逻辑的关键所在。但是上面ListenAndServe方法的Handler参数为nil,Handler为Nil的Server对象如何实现处理请求的逻辑呢?

注意到Server对象的Handler属性的注释有提到如果Handler值为nil,那么Server对象将使用http.DefaultServeMux来处理请求。

http.DefaultServeMux是一个ServeMux对象,ServeMux对象是一个HTTP请求的分发器,将匹配了相应URL的请求分发给相应的处理函数进行处理。其定义如下:

type ServeMux struct {
mu    sync.RWMutex
m     map[string]muxEntry
hosts bool // whether any patterns contain hostnames
}

type muxEntry struct {
h       Handler
pattern string
}

ServeMux正是通过map结构(map[string]muxEntry)来匹配请求和Handler的,起到了路由的作用。并且ServeMux本身也是一个Handler,因为它实现了Handler接口的ServeHTTP方法。

其中Server定义如下:

// A Server defines parameters for running an HTTP server.
// The zero value for Server is a valid configuration.
type Server struct {
Addr    string  // TCP address to listen on, ":http" if empty
Handler Handler // handler to invoke, http.DefaultServeMux if nil

// TLSConfig optionally provides a TLS configuration for use
// by ServeTLS and ListenAndServeTLS. Note that this value is
// cloned by ServeTLS and ListenAndServeTLS, so it's not
// possible to modify the configuration with methods like
// tls.Config.SetSessionTicketKeys. To use
// SetSessionTicketKeys, use Server.Serve with a TLS Listener
// instead.
TLSConfig *tls.Config

// ReadTimeout is the maximum duration for reading the entire
// request, including the body.
//
// Because ReadTimeout does not let Handlers make per-request
// decisions on each request body's acceptable deadline or
// upload rate, most users will prefer to use
// ReadHeaderTimeout. It is valid to use them both.
ReadTimeout time.Duration

// ReadHeaderTimeout is the amount of time allowed to read
// request headers. The connection's read deadline is reset
// after reading the headers and the Handler can decide what
// is considered too slow for the body.
ReadHeaderTimeout time.Duration

// WriteTimeout is the maximum duration before timing out
// writes of the response. It is reset whenever a new
// request's header is read. Like ReadTimeout, it does not
// let Handlers make decisions on a per-request basis.
WriteTimeout time.Duration

// IdleTimeout is the maximum amount of time to wait for the
// next request when keep-alives are enabled. If IdleTimeout
// is zero, the value of ReadTimeout is used. If both are
// zero, ReadHeaderTimeout is used.
IdleTimeout time.Duration

// MaxHeaderBytes controls the maximum number of bytes the
// server will read parsing the request header's keys and
// values, including the request line. It does not limit the
// size of the request body.
// If zero, DefaultMaxHeaderBytes is used.
MaxHeaderBytes int

// TLSNextProto optionally specifies a function to take over
// ownership of the provided TLS connection when an NPN/ALPN
// protocol upgrade has occurred. The map key is the protocol
// name negotiated. The Handler argument should be used to
// handle HTTP requests and will initialize the Request's TLS
// and RemoteAddr if not already set. The connection is
// automatically closed when the function returns.
// If TLSNextProto is not nil, HTTP/2 support is not enabled
// automatically.
TLSNextProto map[string]func(*Server, *tls.Conn, Handler)

// ConnState specifies an optional callback function that is
// called when a client connection changes state. See the
// ConnState type and associated constants for details.
ConnState func(net.Conn, ConnState)

// ErrorLog specifies an optional logger for errors accepting
// connections, unexpected behavior from handlers, and
// underlying FileSystem errors.
// If nil, logging is done via the log package's standard logger.
ErrorLog *log.Logger

disableKeepAlives int32     // accessed atomically.
inShutdown        int32     // accessed atomically (non-zero means we're in Shutdown)
nextProtoOnce     sync.Once // guards setupHTTP2_* init
nextProtoErr      error     // result of http2.ConfigureServer if used

mu         sync.Mutex
listeners  map[*net.Listener]struct{}
activeConn map[*conn]struct{}
doneChan   chan struct{}
onShutdown []func()
}

更多相关技术内容咨询欢迎前往并持续关注六星社区了解详情。

程序员编程交流QQ群:805358732

如果你想用Python开辟副业赚钱,但不熟悉爬虫与反爬虫技术,没有接单途径,也缺乏兼职经验
关注下方微信公众号:Python编程学习圈,获取价值999元全套Python入门到进阶的学习资料以及教程,还有Python技术交流群一起交流学习哦。

attachments-2022-06-hZUR6D3l62ad2c67a26d1.jpeg

  • 发表于 2021-06-30 11:18
  • 阅读 ( 1062 )
  • 分类:Golang

0 条评论

请先 登录 后评论
轩辕小不懂
轩辕小不懂

2403 篇文章

作家榜 »

  1. 轩辕小不懂 2403 文章
  2. 小柒 1324 文章
  3. Pack 1135 文章
  4. Nen 576 文章
  5. 王昭君 209 文章
  6. 文双 71 文章
  7. 小威 64 文章
  8. Cara 36 文章