首頁 > 後端開發 > Golang > 主體

Golang如何實現簡單的API網關

藏色散人
發布: 2020-08-31 17:07:02
轉載
3668 人瀏覽過

下面由#Golang教學欄目跟大家介紹Golang實作簡單的API網關的方法,希望對需要的朋友有幫助!

Golang如何實現簡單的API網關

在最近的一個專案中,採用了微服務架構-go-kit進行後端的開發。在微服務架構風格中,一個大應用被拆分成為了多個小的服務系統提供出來,這些小的系統他們可以自成體系,也就是說這些小系統可以擁有自己的資料庫,框架甚至語言等,因此我們需要設計一個API 網關(API Gataway),其實網路上已經有較多現成的實作框架,但是本專案的需求是比較簡單的,因此將使用Golang自行實現。

實作

API網關是伺服器,是系統的唯一入口。從物件導向設計的角度來看,它與外觀模式類似。 API閘道封裝了系統內部架構,為每個客戶端提供一個客製化的API。它可能還具有其它職責,如身份驗證、監控、負載平衡、快取、請求分片與管理、靜態回應處理。

用於實作API閘道的技術很多,大致上分為這麼幾類:

  • #通用反向代理:NginxHaproxy、…
  • 網路程式框架:NettyServlet、…
  • API網關框架:Spring Cloud GatewayZuulZuul2、…

API閘道最基本的功能就是反向代理。其實作方式有很多,本文將基於標準函式庫net/http/httputil包中的ReverseProxy型別來實作一個簡單的反向代理程式。反向代理的實作主要涉及到func NewSingleHostReverseProxy(target *url.URL) *ReverseProxytype ReverseProxy

func NewSingleHostReverseProxy(target *url.URL) *ReverseProxy
登入後複製
// NewSingleHostReverseProxy returns a new ReverseProxy that routes// URLs to the scheme, host, and base path provided in target. If the// target's path is "/base" and the incoming request was for "/dir",// the target request will be for /base/dir.// NewSingleHostReverseProxy does not rewrite the Host header.// To rewrite Host headers, use ReverseProxy directly with a custom// Director policy.func NewSingleHostReverseProxy(target *url.URL) *ReverseProxy {
	targetQuery := target.RawQuery
	director := func(req *http.Request) {
		req.URL.Scheme = target.Scheme
		req.URL.Host = target.Host
		req.URL.Path = singleJoiningSlash(target.Path, req.URL.Path)
		if targetQuery == "" || req.URL.RawQuery == "" {
			req.URL.RawQuery = targetQuery + req.URL.RawQuery		} else {
			req.URL.RawQuery = targetQuery + "&" + req.URL.RawQuery		}
		if _, ok := req.Header["User-Agent"]; !ok {
			// explicitly disable User-Agent so it's not set to default value
			req.Header.Set("User-Agent", "")
		}
	}
	return &ReverseProxy{Director: director}}
登入後複製

NewSingleHostReverseProxy傳回一個新的ReverseProxy,將URLs請求路由到targe的指定的 scheme, host, base path

// ReverseProxy is an HTTP Handler that takes an incoming request and// sends it to another server, proxying the response back to the// client.type ReverseProxy struct {
	// Director must be a function which modifies
	// the request into a new request to be sent
	// using Transport. Its response is then copied
	// back to the original client unmodified.
	// Director must not access the provided Request
	// after returning.
	Director func(*http.Request)

	Transport http.RoundTripper

	FlushInterval time.Duration

	ErrorLog *log.Logger

	BufferPool BufferPool	// ModifyResponse is an optional function that modifies the
	// Response from the backend. It is called if the backend
	// returns a response at all, with any HTTP status code.
	// If the backend is unreachable, the optional ErrorHandler is
	// called without any call to ModifyResponse.
	//
	// If ModifyResponse returns an error, ErrorHandler is called
	// with its error value. If ErrorHandler is nil, its default
	// implementation is used.
	ModifyResponse func(*http.Response) error

	ErrorHandler func(http.ResponseWriter, *http.Request, error)}
登入後複製

ReverseProxy類型有兩個重要的屬性,分別是DirectorModifyResponse,這兩個屬性都是函數類型,在接收到客戶端請求時,ServeHTTP函數首先呼叫Director函數對接受到的請求體進行修改,例如修改請求的目標位址、請求頭等;然後使用修改後的請求體發起新的請求,接收到回應後,呼叫ModifyResponse函數對回應進行修改,最後將修改後的回應體拷貝並回應給客戶端,這樣就實現了反向代理的整個流程。

NewSingleHostReverseProxy中原始碼已經對傳入的URLs進行解析並且完成了Director的修改,我們只需要呼叫 NewSingleHostReverseProxy函數並且傳入目標伺服器的URL即可,一個簡單的反向代理就完成了啦。

程式碼

實例程式碼只涉及微服務中userauth模組,可以依照實際需求自行修改部分

package mainimport (
	"fmt"
	"log"
	"net/http"
	"net/http/httputil"
	"net/url"
	"strings")type handle struct {
	host string
	port string}type Service struct {
	auth *handle
	user *handle}func (this *Service) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	var remote *url.URL	if strings.Contains(r.RequestURI, "api/auth") {
		remote, _ = url.Parse("http://" + this.auth.host + ":" + this.auth.port)
	} else if strings.Contains(r.RequestURI, "api/user") {
		remote, _ = url.Parse("http://" + this.user.host + ":" + this.user.port)
	} else {
		fmt.Fprintf(w, "404 Not Found")
		return
	}
	proxy := httputil.NewSingleHostReverseProxy(remote)
	proxy.ServeHTTP(w, r)}func startServer() {
	// 注册被代理的服务器 (host, port)
	service := &Service{
		auth: &handle{host: "127.0.0.1", port: "8081"},
		user: &handle{host: "127.0.0.1", port: "8082"},
	}
	err := http.ListenAndServe(":8888", service)
	if err != nil {
		log.Fatalln("ListenAndServe: ", err)
	}}func main() {
	startServer()}
登入後複製

以上是Golang如何實現簡單的API網關的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:csdn.net
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!