帶入gRPC:讓你的服務(wù)同時提供 HTTP 接口

前言

  • 接口需要提供給其他業(yè)務(wù)組訪問询刹,但是 RPC 協(xié)議不同無法內(nèi)調(diào)谜嫉,對方問能否走 HTTP 接口,怎么辦凹联?
  • 微信(公眾號沐兰、小程序)等第三方回調(diào)接口只支持 HTTP 接口,怎么辦

我相信你在實際工作中都會遇到如上問題蔽挠,在 gRPC 中都是有解決方案的住闯,本章節(jié)將會進(jìn)行介紹 ??

為什么可以同時提供 HTTP 接口

關(guān)鍵一點,gRPC 的協(xié)議是基于 HTTP/2 的澳淑,因此應(yīng)用程序能夠在單個 TCP 端口上提供 HTTP/1.1 和 gRPC 接口服務(wù)(兩種不同的流量)

怎么同時提供 HTTP 接口

檢測協(xié)議
if r.ProtoMajor == 2 && strings.Contains(r.Header.Get("Content-Type"), "application/grpc") {
    server.ServeHTTP(w, r)
} else {
    mux.ServeHTTP(w, r)
}
流程
  1. 檢測請求協(xié)議是否為 HTTP/2
  2. 判斷 Content-Type 是否為 application/grpc(gRPC 的默認(rèn)標(biāo)識位)
  3. 根據(jù)協(xié)議的不同轉(zhuǎn)發(fā)到不同的服務(wù)處理

gRPC

TLS

在前面的章節(jié)比原,為了便于展示因此沒有簡單封裝

在本節(jié)需復(fù)用代碼,重新封裝了杠巡,可詳見:go-grpc-example

目錄結(jié)構(gòu)

新建 simple_http_client量窘、simple_http_server 目錄,目錄結(jié)構(gòu)如下:

go-grpc-example
├── client
│   ├── simple_client
│   ├── simple_http_client
│   └── stream_client
├── conf
├── pkg
│   └── gtls
├── proto
├── server
│   ├── simple_http_server
│   ├── simple_server
│   └── stream_server
Server

在 simple_http_server 目錄下新建 server.go氢拥,寫入文件內(nèi)容:

package main

import (
    "context"
    "log"
    "net/http"
    "strings"

    "github.com/EDDYCJY/go-grpc-example/pkg/gtls"
    pb "github.com/EDDYCJY/go-grpc-example/proto"

    "google.golang.org/grpc"
)

type SearchService struct{}

func (s *SearchService) Search(ctx context.Context, r *pb.SearchRequest) (*pb.SearchResponse, error) {
    return &pb.SearchResponse{Response: r.GetRequest() + " HTTP Server"}, nil
}

const PORT = "9003"

func main() {
    certFile := "../../conf/server/server.pem"
    keyFile := "../../conf/server/server.key"
    tlsServer := gtls.Server{
        CertFile: certFile,
        KeyFile:  keyFile,
    }

    c, err := tlsServer.GetTLSCredentials()
    if err != nil {
        log.Fatalf("tlsServer.GetTLSCredentials err: %v", err)
    }

    mux := GetHTTPServeMux()

    server := grpc.NewServer(grpc.Creds(c))
    pb.RegisterSearchServiceServer(server, &SearchService{})

    http.ListenAndServeTLS(":"+PORT,
        certFile,
        keyFile,
        http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            if r.ProtoMajor == 2 && strings.Contains(r.Header.Get("Content-Type"), "application/grpc") {
                server.ServeHTTP(w, r)
            } else {
                mux.ServeHTTP(w, r)
            }

            return
        }),
    )
}

func GetHTTPServeMux() *http.ServeMux {
    mux := http.NewServeMux()
    mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("eddycjy: go-grpc-example"))
    })

    return mux
}
  • http.NewServeMux:創(chuàng)建一個新的 ServeMux蚌铜,ServeMux 本質(zhì)上是一個路由表。它默認(rèn)實現(xiàn)了 ServeHTTP嫩海,因此返回 Handler 后可直接通過 HandleFunc 注冊 pattern 和處理邏輯的方法
  • http.ListenAndServeTLS:可簡單的理解為提供監(jiān)聽 HTTPS 服務(wù)的方法厘线,重點的協(xié)議判斷轉(zhuǎn)發(fā),也在這里面

其實出革,你理解后就會覺得很簡單,核心步驟:判斷 -> 轉(zhuǎn)發(fā) -> 響應(yīng)渡讼。我們改變了前兩步的默認(rèn)邏輯骂束,僅此而已

Client

在 simple_http_server 目錄下新建 client.go,寫入文件內(nèi)容:

package main

import (
    "context"
    "log"

    "google.golang.org/grpc"

    "github.com/EDDYCJY/go-grpc-example/pkg/gtls"
    pb "github.com/EDDYCJY/go-grpc-example/proto"
)

const PORT = "9003"

func main() {
    tlsClient := gtls.Client{
        ServerName: "go-grpc-example",
        CertFile:   "../../conf/server/server.pem",
    }
    c, err := tlsClient.GetTLSCredentials()
    if err != nil {
        log.Fatalf("tlsClient.GetTLSCredentials err: %v", err)
    }

    conn, err := grpc.Dial(":"+PORT, grpc.WithTransportCredentials(c))
    if err != nil {
        log.Fatalf("grpc.Dial err: %v", err)
    }
    defer conn.Close()

    client := pb.NewSearchServiceClient(conn)
    resp, err := client.Search(context.Background(), &pb.SearchRequest{
        Request: "gRPC",
    })
    if err != nil {
        log.Fatalf("client.Search err: %v", err)
    }

    log.Printf("resp: %s", resp.GetResponse())
}

驗證

gRPC Client
$ go run client.go 
2018/10/04 14:56:56 resp: gRPC HTTP Server
HTTP/1.1 訪問

總結(jié)

通過本章節(jié)成箫,表面上完成了同端口提供雙服務(wù)的功能展箱,但實際上,應(yīng)該是加深了 HTTP/2 的理解和使用蹬昌,這才是本質(zhì)

拓展

如果你有一個需求混驰,是要同時提供 RPC 和 RESTful JSON API 兩種接口的,不要猶豫皂贩,點進(jìn)去:gRPC + gRPC Gateway 實踐

問題

你以為這個方案就萬能了嗎栖榨,不。Envoy Proxy 的支持就不完美明刷,無法同時監(jiān)聽一個端口的兩種流量 ??

參考

本系列示例代碼

系列目錄

原文地址:帶入gRPC:讓你的服務(wù)同時提供 HTTP 接口
項目地址:https://github.com/EDDYCJY/go...

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末婴栽,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子辈末,更是在濱河造成了極大的恐慌愚争,老刑警劉巖映皆,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異轰枝,居然都是意外死亡捅彻,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進(jìn)店門鞍陨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來步淹,“玉大人,你說我怎么就攤上這事湾戳∠涂酰” “怎么了?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵砾脑,是天一觀的道長幼驶。 經(jīng)常有香客問我,道長韧衣,這世上最難降的妖魔是什么盅藻? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮畅铭,結(jié)果婚禮上氏淑,老公的妹妹穿的比我還像新娘。我一直安慰自己硕噩,他們只是感情好假残,可當(dāng)我...
    茶點故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著炉擅,像睡著了一般辉懒。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上谍失,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天眶俩,我揣著相機(jī)與錄音,去河邊找鬼快鱼。 笑死颠印,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的抹竹。 我是一名探鬼主播线罕,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼窃判!你這毒婦竟也來了闻坚?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤兢孝,失蹤者是張志新(化名)和其女友劉穎窿凤,沒想到半個月后仅偎,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡雳殊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年橘沥,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片夯秃。...
    茶點故事閱讀 38,724評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡座咆,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出仓洼,到底是詐尸還是另有隱情介陶,我是刑警寧澤,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布色建,位于F島的核電站哺呜,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏箕戳。R本人自食惡果不足惜某残,卻給世界環(huán)境...
    茶點故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望陵吸。 院中可真熱鬧玻墅,春花似錦、人聲如沸壮虫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽囚似。三九已至赏酥,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間谆构,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工框都, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留搬素,地道東北人。 一個月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓魏保,卻偏偏與公主長得像熬尺,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子谓罗,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,627評論 2 350

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

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理粱哼,服務(wù)發(fā)現(xiàn),斷路器檩咱,智...
    卡卡羅2017閱讀 134,637評論 18 139
  • 原文連接: 一文了解RPC以及gRPC基于Golang和Java的簡單實現(xiàn) 一:什么是RPC 簡介:RPC:Re...
    賈順閱讀 8,882評論 2 12
  • (目前有點亂揭措,先貼上來胯舷,等以后有時間在整理吧。這個問題一直想拿出來分享绊含,還有兩個博客桑嘶,都是相關(guān)的,一點點發(fā)出來) ...
    kamiSDY閱讀 4,357評論 0 2
  • 坐復(fù)興號高鐵往返雙城 為了溫暖的相聚 端午躬充、夏至 落地的愛情是長情
    TheRainbowMe閱讀 136評論 0 1
  • 輕盈透亮 2018.08.24 金懌 閱讀 125 相逢是首歌 今天體重輕了兩斤逃顶,三天就變得輕盈了一些,不是為了減...
    屈婧閱讀 366評論 0 0