<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                # 流程 從不同的視角去看待web應用的流程: - 使用者視角:程序員如何使用gin來編寫業務邏輯 - 應用初始化:當進程啟動時gin內部是如何初始化的 - 請求生命周期:當一個HTTP請求來到服務器時后如何轉化為響應 說這些之前了解一下Context這個結構體 ## Context結構體 簡單介紹一下gin框架里面最重要的結構體`Context`,另外一個最重要的結構體是`Engine`,它作為單例存在;而`Context`是從對象池中得到。 ``` // Context作為一個數據結構在中間件中傳遞本次請求的各種數據、管理流程,進行響應 // context.go:40 type Context struct { // ServeHTTP的第二個參數: request Request *http.Request // 用來響應 Writer ResponseWriter writermem responseWriter // URL里面的參數,比如:/xx/:id Params Params // 參與的處理者(中間件 + 請求處理者列表) handlers HandlersChain // 當前處理到的handler的下標 index int8 // Engine單例 engine *Engine // 在context可以設置的值 Keys map[string]interface{} // 一系列的錯誤 Errors errorMsgs // Accepted defines a list of manually accepted formats for content negotiation. Accepted []string } // response_writer.go:20 type ResponseWriter interface { http.ResponseWriter //嵌入接口 http.Hijacker //嵌入接口 http.Flusher //嵌入接口 http.CloseNotifier //嵌入接口 // 返回當前請求的 response status code Status() int // 返回寫入 http body的字節數 Size() int // 寫string WriteString(string) (int, error) //是否寫出 Written() bool // 強制寫htp header (狀態碼 + headers) WriteHeaderNow() } // response_writer.go:40 // 實現 ResponseWriter 接口 type responseWriter struct { http.ResponseWriter size int status int } type errorMsgs []*Error // 每當一個請求來到服務器,都會從對象池中拿到一個context。其函數有: // **** 創建 reset() //從對象池中拿出來后需要初始化 Copy() *Context //克隆,用于goroute中 HandlerName() string //得到最后那個處理者的名字 Handler() //得到最后那個Handler // **** 流程控制 Next() // 只能在中間件中使用,依次調用各個處理者 IsAborted() bool Abort() // 廢棄 AbortWithStatusJson(code int, jsonObj interface{}) AbortWithError(code int, err error) *Error // **** 錯誤管理 Error(err error) *Error // 給本次請求添加個錯誤。將錯誤收集然后用中間件統一處理(打日志|入庫)是一個比較好的方案 // **** 元數據管理 Set(key string, value interface{}) //本次請求用戶設置各種數據 (Keys 字段) Get(key string)(value interface{}, existed bool) MustGet(key string)(value interface{}) GetString(key string) string GetBool(key string) bool GetInt(key string) int GetInt64(key string) int64 GetFloat64(key string) float64 GetTime(key string) time.Time GetDuration(key string) time.Duration GetStringSlice(key string) []string GetStringMap(key string) map[string]interface{} GetStringMapString(key string) map[string]string GetStringMapStringSlice(key string) map[string][]string // **** 輸入數據 //從URL中拿值,比如 /user/:id => /user/john Param(key string) string //從GET參數中拿值,比如 /path?id=john GetQueryArray(key string) ([]string, bool) GetQuery(key string)(string, bool) Query(key string) string DefaultQuery(key, defaultValue string) string GetQueryArray(key string) ([]string, bool) QueryArray(key string) []string //從POST中拿數據 GetPostFormArray(key string) ([]string, bool) PostFormArray(key string) []string GetPostForm(key string) (string, bool) PostForm(key string) string DefaultPostForm(key, defaultValue string) string // 文件 FormFile(name string) (*multipart.FileHeader, error) MultipartForm() (*multipart.Form, error) SaveUploadedFile(file *multipart.FileHeader, dst string) error // 數據綁定 Bind(obj interface{}) error //根據Content-Type綁定數據 BindJSON(obj interface{}) error BindQuery(obj interface{}) error //--- Should ok, else return error ShouldBindJSON(obj interface{}) error ShouldBind(obj interface{}) error ShouldBindJSON(obj interface{}) error ShouldBindQuery(obj interface{}) error //--- Must ok, else SetError MustBindJSON(obj interface{}) error ClientIP() string ContentType() string IsWebsocket() bool // **** 輸出數據 Status(code int) // 設置response code Header(key, value string) // 設置header GetHeader(key string) string GetRawData() ([]byte, error) Cookie(name string) (string, error) // 設置cookie SetCookie(name, value string, maxAge int, path, domain string, secure, httpOnly bool) Render(code int, r render.Render) // 數據渲染 HTML(code int, name string, obj interface{}) //HTML JSON(code int, obj interface{}) //JSON IndentedJSON(code int, obj interface{}) SecureJSON(code int, obj interface{}) JSONP(code int, obj interface{}) //jsonp XML(code int, obj interface{}) //XML YAML(code int, obj interface{}) //YAML String(code int, format string, values ...interface{}) //string Redirect(code int, location string) // 重定向 Data(code int, contentType string, data []byte) // []byte File(filepath string) // file SSEvent(name string, message interface{}) // Server-Sent Event Stream(step func(w io.Writer) bool) // stream // **** 實現 context.Context 接口(GOROOT中) ``` ## 使用者視角 > 編程其實是嘗試的過程,通過反饋不斷的修正。 ### 簡單的例子 ``` // step1: 得到gin go get github.com/gin-gonic/gin // step2: 編輯main.go import ( "net/http" "github.com/gin-gonic/gin" ) func main() { // 創建一個Engine r := gin.New() // 定義一個處理者 r.GET("/", func(c *gin.Context) { c.String(http.StatusOK, "Hello World!") }) // 再定義一個處理者 r.POST("/ping", func(c *gin.Context) { c.String(http.StatusOK, "pong") }) // 讓其運行起來 r.Run("0.0.0.0:8888) } // step3: 運行 go run main.go ``` ### 使用路由組和中間件 ``` import ( "net/http" "github.com/gin-gonic/gin" ) func main() { r := gin.New() // 使用日志插件 r.Use(gin.Logger()) r.GET("/", func(c *gin.Context) { c.String(http.StatusOK, "Hello world") }) r.POST("/ping", func(c *gin.Context) { c.String(http.StatusOK, "pong") }) // 使用路由組 authGroup := r.Group("/auth", func(c *gin.Context) { token := c.Query("token") if token != "123456" { c.AbortWithStatusJSON(200, map[string]string{ "code": "401", "msg": "auth fail", }) } c.Next() }) // 注冊 /auth/info 處理者 authGroup.GET("/info", func(c *gin.Context) { c.JSON(200, map[string]string{ "id": "1234", "name": "name", }) }) r.Run("0.0.0:8910") } ``` 很簡單的注冊就可以讓應用跑起來了。 ## 應用初始化 當我們運行 `go run main.go` 時gin都做了什么呢? 其實golang原生就支持http請求應用開發,任何golang web框架的本質只能是作為工具集存在的。 官方文檔 [Writing Web Applications](https://golang.org/doc/articles/wiki/)介紹了如何寫一個web應用。 示例代碼: ``` // demo1 import ( "net/http" ) func main() { http.HandleFunc("/info", func(response http.ResponseWriter, request *http.Request) { response.Write([]byte("info")) }) http.ListenAndServe(":8888", nil) } // demo2 import ( "net/http" ) type Handle struct{} func (h Handle) ServeHTTP(response http.ResponseWriter, request *http.Request) { switch request.URL.Path { case "/info": response.Write([]byte("info")) default: } } func main() { http.ListenAndServe(":8888", Handle{}) } ``` 上面兩個代碼非常簡單,但是就可以在服務器上開始一個web應用。 而gin的本質也就是使用demo2的代碼,進行封裝,提供工具函數,方便業務開發。 回到本章的主題,應用初始化大概的過程包括: - 創建一個 Engine 對象 - 注冊中間件 - 注冊路由(組) ## 請求生命周期 因為golang原生為web而生而提供了完善的功能,用戶需要關注的東西大多數是業務邏輯本身了。 gin能做的事情也是去把 `ServeHTTP(ResponseWriter, *Request)` 做得高效、友好。 一個請求來到服務器了,`ServeHTTP` 會被調用,gin做的事情包括: - 路由,找到handle - 將請求和響應用Context包裝起來供業務代碼使用 - 依次調用中間件和處理函數 - 輸出結果
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看