go restful源碼剖析-4

綜述


調(diào)試樣例為examples\restful-encoding-filter.go栈虚,在該例子中主要引入了Path嗜诀、Comsumer屈暗、Produces的概念,代碼如下屏富。

func main() {
    restful.Add(NewUserService())
    log.Print("start listening on localhost:8080")
    log.Fatal(http.ListenAndServe(":8080", nil))
}

func NewUserService() *restful.WebService {
    ws := new(restful.WebService)
    ws.
        Path("/users").
        Consumes(restful.MIME_XML, restful.MIME_JSON).
        Produces(restful.MIME_JSON, restful.MIME_XML)

    // install a response encoding filter
    ws.Route(ws.GET("/{user-id}").Filter(encodingFilter).To(findUser))
    return ws
}

// Route Filter (defines FilterFunction)
func encodingFilter(req *restful.Request, resp *restful.Response, chain *restful.FilterChain) {
    log.Printf("[encoding-filter] %s,%s\n", req.Request.Method, req.Request.URL)
    // wrap responseWriter into a compressing one
    compress, _ := restful.NewCompressingResponseWriter(resp.ResponseWriter, restful.ENCODING_GZIP)
    resp.ResponseWriter = compress
    defer func() {
        compress.Close()
    }()
    chain.ProcessFilter(req, resp)
}

// GET http://localhost:8080/users/42
//
func findUser(request *restful.Request, response *restful.Response) {
    log.Print("findUser")
    response.WriteEntity(User{"42", "Gandalf"})
}

Path添加流程


ws.Path("/users")在之前的樣例中晴竞,都沒有設(shè)置過rootpath,restful中通過調(diào)用Path函數(shù)狠半,改變web service中的root path噩死。

func (w *WebService) Path(root string) *WebService {
    w.rootPath = root
    if len(w.rootPath) == 0 {
        w.rootPath = "/"
    }
    w.compilePathExpression()
    return w
}

在該函數(shù)中首先將web service的root path設(shè)置為傳入的/user, 并且將調(diào)用compilePathExpression生成對應(yīng)的的path匹配規(guī)則

func (w *WebService) compilePathExpression() {
    compiled, err := newPathExpression(w.rootPath)
    if err != nil {
        log.Printf("invalid path:%s because:%v", w.rootPath, err)
        os.Exit(1)
    }
    w.pathExpr = compiled
}
func newPathExpression(path string) (*pathExpression, error) {
    expression, literalCount, varNames, varCount, tokens := templateToRegularExpression(path)
    compiled, err := regexp.Compile(expression)
    if err != nil {
        return nil, err
    }
    return &pathExpression{literalCount, varNames, varCount, compiled, expression, tokens}, nil
}

在處理過程中,對web service的rootpath進行加工神年,產(chǎn)出expression=^/users(/.*)?$已维、token=/hello,并創(chuàng)建pathExpression對象返回已日。

type pathExpression struct {
    LiteralCount int      // the number of literal characters (means those not resulting from template variable substitution)
    VarNames     []string // the names of parameters (enclosed by {}) in the path
    VarCount     int      // the number of named parameters (enclosed by {}) in the path
    Matcher      *regexp.Regexp
    Source       string // Path as defined by the RouteBuilder
    tokens       []string
}

[圖片上傳失敗...(image-306dc5-1535615090387)]

consumer及producer賦值及生效


在web service中consumer及producer各是一組屬性垛耳,通過對應(yīng)的接口可以直接給對應(yīng)的屬性賦值

// Produces specifies that this WebService can produce one or more MIME types.
// Http requests must have one of these values set for the Accept header.
func (w *WebService) Produces(contentTypes ...string) *WebService {
    w.produces = contentTypes
    return w
}

// Consumes specifies that this WebService can consume one or more MIME types.
// Http requests must have one of these values set for the Content-Type header.
func (w *WebService) Consumes(accepts ...string) *WebService {
    w.consumes = accepts
    return w
}

最終consumes生效在進行route匹配過程中,當(dāng)http訪問中飘千,在獲取route的函數(shù)中detectRoute

    for _, each := range methodOk {
        if each.matchesContentType(contentType) {
            inputMediaOk = append(inputMediaOk, each)
        }
    }

會執(zhí)行matchesContentType艾扮,在這個函數(shù)中,將會從ws中獲取到consumer檢查用戶的http content type是否符合consumer的設(shè)置占婉,而produces的生效是用戶調(diào)用WriteEntity函數(shù)時泡嘴,調(diào)用EntityWriter使用。

// WriteEntity calls WriteHeaderAndEntity with Http Status OK (200)
func (r *Response) WriteEntity(value interface{}) error {
    return r.WriteHeaderAndEntity(http.StatusOK, value)
}
func (r *Response) EntityWriter() (EntityReaderWriter, bool) {
    sorted := sortedMimes(r.requestAccept)
    for _, eachAccept := range sorted {
        for _, eachProduce := range r.routeProduces {
            if eachProduce == eachAccept.media {
                if w, ok := entityAccessRegistry.accessorAt(eachAccept.media); ok {
                    return w, true
                }
            }
        }
        if eachAccept.media == "*/*" {
            for _, each := range r.routeProduces {
                if w, ok := entityAccessRegistry.accessorAt(each); ok {
                    return w, true
                }
            }
        }
    }
    // if requestAccept is empty
    writer, ok := entityAccessRegistry.accessorAt(r.requestAccept)
    if !ok {
        // if not registered then fallback to the defaults (if set)
        if DefaultResponseMimeType == MIME_JSON {
            return entityAccessRegistry.accessorAt(MIME_JSON)
        }
        if DefaultResponseMimeType == MIME_XML {
            return entityAccessRegistry.accessorAt(MIME_XML)
        }
        // Fallback to whatever the route says it can produce.
        // https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
        for _, each := range r.routeProduces {
            if w, ok := entityAccessRegistry.accessorAt(each); ok {
                return w, true
            }
        }
        if trace {
            traceLogger.Printf("no registered EntityReaderWriter found for %s", r.requestAccept)
        }
    }
    return writer, ok
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末逆济,一起剝皮案震驚了整個濱河市酌予,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌奖慌,老刑警劉巖抛虫,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異简僧,居然都是意外死亡建椰,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進店門岛马,熙熙樓的掌柜王于貴愁眉苦臉地迎上來棉姐,“玉大人,你說我怎么就攤上這事啦逆∩【兀” “怎么了?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵夏志,是天一觀的道長乃坤。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么湿诊? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任狱杰,我火速辦了婚禮,結(jié)果婚禮上厅须,老公的妹妹穿的比我還像新娘浦旱。我一直安慰自己,他們只是感情好九杂,可當(dāng)我...
    茶點故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布颁湖。 她就那樣靜靜地躺著,像睡著了一般例隆。 火紅的嫁衣襯著肌膚如雪甥捺。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天镀层,我揣著相機與錄音镰禾,去河邊找鬼。 笑死唱逢,一個胖子當(dāng)著我的面吹牛吴侦,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播坞古,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼备韧,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了痪枫?” 一聲冷哼從身側(cè)響起织堂,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎奶陈,沒想到半個月后易阳,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡吃粒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年潦俺,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片徐勃。...
    茶點故事閱讀 38,617評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡事示,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出疏旨,到底是詐尸還是另有隱情很魂,我是刑警寧澤扎酷,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布檐涝,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏谁榜。R本人自食惡果不足惜幅聘,卻給世界環(huán)境...
    茶點故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望窃植。 院中可真熱鬧帝蒿,春花似錦、人聲如沸巷怜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽延塑。三九已至绣张,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間关带,已是汗流浹背侥涵。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留宋雏,地道東北人芜飘。 一個月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像磨总,于是被迫代替她去往敵國和親嗦明。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,486評論 2 348

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理蚪燕,服務(wù)發(fā)現(xiàn)招狸,斷路器,智...
    卡卡羅2017閱讀 134,629評論 18 139
  • restful hello world 首次瀏覽下go-restful的工程結(jié)構(gòu)邻薯,從工程組織上面來看裙戏,工程包括兩個...
    tcuze閱讀 580評論 0 1
  • 姓名:周小蓬 16019110037 轉(zhuǎn)載自:http://blog.csdn.net/YChenFeng/art...
    aeytifiw閱讀 34,712評論 13 425
  • 有時候,開始比堅持更艱難厕诡,但有時候累榜,開始了之后堅持就會變得簡單。
    墨中人閱讀 131評論 0 0
  • 占高姿灵嫌,樹正氣壹罚,顯德行,朔本歸源寿羞,細(xì)至精妙猖凛,開格局,駐情商绪穆,逆思維辨泳,大局者明虱岂,入局者清,明懂而自開菠红,善以身心臨境第岖,...
    夜貓二閱讀 269評論 0 0