Golang如何实现简单的API网关

下面由Golang教程栏目给大家介绍Golang实现简单的API网关的方法 ,希望对需要的朋友有所帮助!

Golang如何实现简单的API网关

在最近的一个项目中,采用了微服务架构-go-kit进行后端的开发。在微服务架构风格中,一个大应用被拆分成为了多个小的服务系统提供出来,这些小的系统他们可以自成体系,也就是说这些小系统可以拥有自己的数据库,框架甚至语言等,因此我们需要设计一个API 网关(API Gataway),其实网上已经有较多现成的实现框架,但是本项目y @ 1 [的需求是比较简单的,因此将使用Golang自行实现。

实现

API网关是一个服务器,是系统的唯一入口。从面向对象设计的角度看,它与外观模式类似。API网关封装g b v r z .了系统内部架构,为每个客户端提供一个定制的API。它可能还具有其它职责,如身份验证、监控、负载均衡、缓存、请求分片与管理、静态响应处理。

用于实现API网关的技术有很多,大致分为这么几类:

  • 通用反向代理:NginxHaproxy、……
  • 网络编程框架:NettyServletE X o Q G……
  • API网关框架:SpM F uring 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 rouN = E T z 6 1 3 3tes// URLs to the scheme, host, and base path provided in target. If the// target's path is "/base" and thf h & ^ k l E d 6e incoming request was for "/dir",// the target reqp : z i G W ; /uest will be for /base/dir.// NewSingleHostReverseProxy dN x h h ; d oes not rewrit^ N $e the Host headeN L , G Hr.// To rewrite Host header5 }  i c Q S $ }s, use ReverseProxy directly with a custom// Director policy.func NewSingleHostReverseProxy(target *url.URL) *ReverseProxy {
targetQuery := target. _ cRawQuery
director := func(req *http.Request) {
req.URL.Scheme = target.Scheme
req.URL.Host = target.Host
reL Q i 8 + v D `q.URL.Path = singleJoiningSlash(target.Path, req.O a k t KURL.Path)
if targetQuery == "" || reqt 9 p ?  6 i.URL.RawQuery == "" {
req.URL.RawQuery = ta! M E * M ! QrgetQuery + req.URQ ) ~ q %  EL.RawQueryv ? k 5 o B		} else {
req.URL.RawQuer! # [ a d e y g fy = targetQuery + "&" + req.URL.RawQuery		}
if _, ok := req.Header["User-Agent"]; !ok {
// explicitly disable User-Age% L l / - m #nt so it's not set: , u C to default value
req.Header.Set("User-Agent"K 3 S I u b L 1, "")
}
}
return &ReverseP` i | [roxy{Director: directoY o ; l 9 : t a hr}}

NewSingleHostRY S t zeverseProxy返回一个新的ReverseProxy,将URLs请求路由到targe的指定的scheme, host, base path

// ReverseProxy is an HTTP Handler that takes an incoming request and// sends it to another server, proE b x R O , W #xying the response back to the// clS | a k Y ? D M 9ient.type ReverseProxy struct {
// Director? S Y mun e u } P 7st be a funcP 5 n 9 b ttion which modifies
// the request into a new request to be sent
// using Transport. Its r- Y 4 e ( : sesponsT = 5e is then/ ; H copied
// back to th8 | J Fe o; Y 6 1 k + L Zriginal client unmodified.
// Director must not acc ( &ess the provided Request
// after returning.
Director func(*http.Request)
Transport ht; t Y ? { j Vtp.RoundTripper
FlusY B . Y s j ThInterval time.Duration
ErrorLog *log.Logger
BufferPool BufferPool	// ModifyRespD b w ponse is an optional function that{ ? 2 I e modifies the
// Response from the backend. It is called if the backend
// returns a response at al@ T x j &l, witj ( ^ N m 2 O 3 /h any HTTP status code.
// If the backend is unreachable, the optional ErrorHandler is
// called withoQ e Mut any call to ModifyResponse.
//
// If ModifyResponse returns an error, Er8 h X G c 7ror0 } * ~ W | eHandler is called
// with its error value. IA j D = Z d J 0f ErrorHandler is nil, its default_ - 0 t k
// implementation is used.
ModifyResponse func(*http.Rez _ qsponse) error
ErrorHandler func(http.ResponseWriter, *http.Request, error)}

ReverseProxy类型有两个重要的属性,分别是DirectorModifyResponse,这两个属性都是函数类型,在接收到客户端请求时,ServeHTTP函数首先调用D) g f : Q virector^ + ` y 8 L数对接r . o K受到的请求体进行修改,例如修改请求的目标地址、请求头等;然后使用修改后的请求体发起新的请求,接收到响应后,调] 1 . ~ %ModifyResponse函数对响应进行修改,最后将修改后的响应体拷贝并响应给O { U s 6 V [客户端,这样就实现了反向代理的整个流程。

NewSingleHostReverseProxy中源码已经对传入的URLs进行解析并且完成了Director的修改,我们只需要调用NewSingleHostReverseProxy函数并且传入目标服务器的URL即可D # c X l H r x m,一个简单的反向代理就完成了啦。

代码

实例代码只涉及微服务中 userauth4 N ? i n * y G p块,可以根据实际需求自行修改部分

package mainimport (
"fmtw d & Q e"
"log"
"net/http"
"net/http/httputil"
"net/url"
"strings")type handle struct {
hO 2 eost string
port strio e i z z ng}typq S ( z N @ Je Service struct {
auth *handle
user *handle}func (this *Service) ServeHTTP(w http.Responsc m 8 k yeWriter,P _ s i N r *http.Request) {
var remote *url.URL	if strings.Contains(r.Reques| K W # G $ S BtURI, "api/auth") {
remote, _ = url.Parse("http://" + this.auth.hostm - | ] _ , ( v + ":" + this.auth.port)
} else if strings.Contains(r.RequestURI, "- S Aapi/user") {
remote, _ = url.Parse("http://" + this.user.host + ":E u t" + this.J F = U H u d - &user.port)Y N I ) w V 7
} else {
fmt.Fprintf(w, "404 Not Found")
return
}
proxy := httputil.NewSingleHostReverseProxy(remote)
proxy.ServeHTTP(w, r)}func startServer() {
// 注册被代理的服务器t D ` ; ; n N (host, port)
service := &Service{
auth: &handle{host: "127.0.0.1", port: "8081"},
user: &handle{host: "127.0.0.1", port: "8082"},
}
err := http.ListenAndm C /Serve(":8888", service)
if err != nil {
log.Fatalln("Li^ - Bstena 5 p V # ! a [AndServe: ", err)
}}func main() {
startServer()}

以上就是Golang如何实现简单的API网关的详细内容。