Gweb Summary of the router

Source: Internet
Author: User
This is a creation in Article, where the information may have evolved or changed.

This code goes

Code structure

.- router包├── middleware│   ├── param.go     // 参数解析支持│   ├── readme.md    // 文档│   ├── reqlog.go    // 记录请求日志│   ├── response.go  // 响应的相关函数│   └── safe.go      // safe recover功能└── router.go        // 入口和request处理逻辑
the entire router is not coupled to the Gweb other modules and will only depend on logger. router.goThis is the entry for the entire route, while middleware provides some tool functions and a simple encapsulation.

Router processing logic

router.goThe following works are mainly done:

    • Define routing, and Controller registration
    • Custom http.Handler , ApiHandler that is, the implementation ServeHTTP method.

Custom Routing route

type Route struct {    Path    string         // req URI    Method  string         // GET,POST...    Fn      interface{}    // URI_METHOD hanlde Func    ReqPool *sync.Pool     // req form pool    ResPool *sync.Pool     // response pool}

Use a structure when using map[string][]*Route to store the URI and method corresponding to the route handler function. Brain repair, the actual storage is this:

{    "/hello": [        &Route{            Path: "/hello",            Method: "GET",            Fn: someGetFunc,            ReqPool: someGetReqPool,            ResPool: someGetRespPool        },        &Route{            Path: "/hello",            Method: "POST",            Fn: somePostFunc,            ReqPool: somePostReqPool,            ResPool: somePostRespPool        },        // ... more    ],    // ... more}
The main purpose of this structure is to support restful APIs, others are not considered for the time being

Apihanlder

router.goDefines one of the ApiHandler following:

type ApiHandler struct {    NotFound         http.Handler    MethodNotAllowed http.Handler}

It simply contains two hander for support 404 and 405 request.

!!!! The point is, why do we have to fix a route like that? How to parse parameters, respond, and process requests? Talk is Cheap, show me the Code

Func (a *apihandler) servehttp (w http. Responsewriter, req *http. Request) {defer middleware. Safehandler (w, req) path: = req. Url. Path route, OK: = Foundroute (path, req.  Method)////handle 404 If!ok {if a.notfound! = Nil {a.notfound.servehttp (W, req)} else {http. NotFound (W, req)} return}//not nil and to, ref to Foundroute if route! = Nil {goto Foun D}////handle 405 If!allowed (path, req.            Method) {if a.methodnotallowed! = Nil {a.methodnotallowed.servehttp (W, req)} else { http. Error (W, http. StatusText (http. statusmethodnotallowed), HTTP. Statusmethodnotallowed,)} return}found:////normal handle Reqres: = route. Reqpool.get () defer route. Reqpool.put (reqres)//Parse params if errs: = middleware. Parseparams (W, req, reqres); Len (errs)! = 0 {JE: = new (middleware).     JSONERR)   Response (JE, newcodeinfo (codeparaminvalid, "")) JE. errs = errs middleware. Responseerrorjson (W, je) return} in: = Make ([]reflect. Value, 1) in[0] = reflect. ValueOf (reqres) Fn: = reflect. ValueOf (route. Fn)////call Web server handle function out: = Fn.call (in)////response to Client resp: = Out[0]. Interface () defer route. Respool.put (RESP) middleware. Responsejson (W, resp) return}

The process is just as you think. Processing 405,405 and so on, then using the route Route , parameter resolution, validation, invocation, return response and other operations. The design reference httprouter . About parameter parsing and response, right away.

Parameter parsing and validation (PARAM.GO)

The
parsing of parameters, the first consideration only get,post,put,delete not consider JSON and file parsing. Because I was busy with the framework at first, and secondly because I used the schema is not supported (I did not look carefully, I realized it is very simple).

Here are two of my favorite Golang third-party libraries, which is also my tool for parameter parsing and validation:

    1. Schema, converts structs to and from form values.
    2. Beego/validation,valid the struct
Parseparams, the parse params into the reqres from req. Form, and support//form-data, json-body//todo:support parse Filefunc parseparams (w http. Responsewriter, req *http. Request, Reqres interface{}) (errs paramerrors) {switch req. Method {case HTTP. Methodget:req. Parseform () Case HTTP. Methodpost, http. Methodput:req. Parsemultipartform (<<) default:req. Parseform ()}//Log request Logreq (req)//If should parse JSON body//parse JSON into reqres if Shoul Dparsejson (reqres) {data, err: = Getjsondata (req) If err! = Nil {errs = append (errs, Newparamer Ror ("Parse.json", err. Error (), "")) return} If Err = json. Unmarshal (data, reqres); Err! = Nil {errs = append (errs, Newparamerror ("Json.unmarshal", err. Error (), "")) return} BS, _: = json. Marshal (reqres) reql.info ("Pasing json Body:" + string (BS)) goto Valid}//If has FILES field,//So Parese req to get attachment files if Shouldparsefile (reqres) {appl.info ("should parse files" ) If Req. Multipartform = = Nil | | Req. Multipartform.file = = Nil {errs = append (errs, Newparamerror ("FILES", "Empty File param", "")) Retu RN} RV: = reflect. ValueOf (reqres). Elem (). Fieldbyname ("FILES")//Typ: = Reflect. ValueOf (reqres). Elem (). Fieldbyname ("FILES"). Type () Filesmap: = reflect. Makemap (RV. Type ())//parse file loop for key, _: = Range req. Multipartform.file {File, file_header, err: = req. Formfile (key) if err! = Nil {errs = append (errs, Newparamerror (fstring ("Parse Request"). Formfile:%s ", key), err. Error (), "")} defer file. Close () Filesmap.setmapindex (reflect. ValueOf (key), reflect. ValueOf (paramfile{file:file, Fileheader:*file_header,}),)}//Loop end//Set value to Reqres.field ' FILES ' Rv.s ET (Filesmap) If Len (errs)! = 0 {return}}//decode if ERR: = decoder. Decode (Reqres, req. Form); Err! = Nil {errs = append (errs, Newparamerror ("decoder", err. Error (), "")) return}valid://Valid V: = Poolvalid.get (). (*valid. Validation) If OK, err: = V.valid (reqres); Err! = Nil {errs = append (errs, Newparamerror ("Validation", err. Error (), ""))} else if!ok {for _, err: = Range v.errors {errs = append (errs, Newparamerrorfromval Iderror (Err)}}} return}

Maybe someone will care shouldParseJson how it's done? As follows:

// shouldParseJson check `i` has field `JSON`func shouldParseJson(i interface{}) bool {    v := reflect.ValueOf(i).Elem()    if _, ok := v.Type().FieldByName("JSON"); !ok {        return false    }    return true}

This enforces that the reqres must contain a JSON field to parse the jsonbody, which must be included to FILES parse the file in the request. So when it comes to writing business logic, this looks like this, and these examples are all in the demo:

/* * json-body Demo */type hellojsonbodyform struct {json bool ' schema: "-" JSON: "-" '//Note schema tag to set "-" Name str ing ' schema: ' name ' valid: ' Required ' json: ' name ' ' Age int ' schema: ' Age ' valid: ' Required; Min (0) "JSON:" Age "'}var poolhellojsonbodyform = &sync.  Pool{new:func () interface{} {return &hellojsonbodyform{}}}type hellojsonbodyresp struct {codeinfo Tip string ' JSON: ' Tip ' '}var poolhellojsonbodyresp = &sync. Pool{new:func () interface{} {return &hellojsonbodyresp{}}}func hellojsonbody (req *hellojsonbodyform) * Hellojsonbodyresp {resp: = Poolhellojsonbodyresp.get (). ( *HELLOJSONBODYRESP) defer poolhellojsonbodyresp.put (RESP) resp. Tip = FMT. Sprintf ("Json-body Hello,%s! Your age[%d] is valid to access, req. Name, req. Age) Response (resp, Newcodeinfo (Codeok, "")) return resp}/* * File hanlder demo */type hellofileform struct {FIL ES MAP[STRING]MW.      Paramfile ' Schema: "-" JSON: "-" '//Note schema tag settings "-" and the type of files remains the Name string            ' Schema: ' name ' valid: ' Required ' ' age int ' schema: ' Age ' valid: ' Required ' '}var Poolhell Ofileform = &sync.        Pool{new:func () interface{} {return &hellofileform{}}}type hellofileresp struct {codeinfo Data struct { Tip string ' JSON: ' Tip ' ' name string ' JSON: ' name ' ' Age int ' json: ' Age ' '} ' JSON: ' Data ' '}var poolhe Llofileresp = &sync. Pool{new:func () interface{} {return &hellofileresp{}}}func hellofile (req *hellofileform) *hellofileresp {resp: = Poolhellofileresp.get (). (*HELLOFILERESP) Defer poolhellofileresp.put (RESP) resp. Data.tip = "foo" for key, Paramfile: = Range req. FILES {appl.infof ("%s:%s\n", Key, ParamFile.FileHeader.Filename) s, _: = Bufio. Newreader (Paramfile.file). ReadString (0) resp. Data.tip + = s} resp. Data.name = req. Name resp. Data.age = req. Age Response (RESP, Newcodeinfo (Codeok, "")) Return RESP}

Response (Response.go)

gwebThe goal is to summarize a Json Web service structure that interacts with the data format. The response body is designed as follows:

{    "code": 0,     // 错误码,或许应该使用“error_code”, 不过不影响    "message": ""  // 错误消息    "user": {        "name": "yep",        // ... other    }}

Combined with the above demo, it is probably seen, the response and no fancy features. Just need to convert the use into a *resp json.Marshal string and send it to the client.

    // ...    //// Call web server handle function    out := Fn.Call(in)    //// response to client    resp := out[0].Interface()    defer route.ResPool.Put(resp)    middleware.ResponseJson(w, resp)

Routing here also ends, although the most important, but still relatively simple.

Finally, you might need a diagram to illustrate?

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.