golang反向代理使用

本文介绍了如何在Golang中实现反向代理,重点展示了使用httputil.NewSingleHostReverseProxy实现简单代理,并讨论了处理鉴权信息的注意事项。通过判断请求路径,实现了根据固定服务转发到对应接口的功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这里插入图片描述
图片引用网络。
反向代理具体含义这里就不在进行讲述了,想看详细信息,可自行百度查看。
我们这里直接上代码进行描述。

package main
 
import (
    _ "fmt"
    "io"
    _ "log"
    "net/http"
    "net/http/httputil"
    "net/url"
    _ "strings"
)
 
func main() {
    /*localHost := "127.0.0.1:8080"
    targetHost := "127.0.0.1:8802"
    httpsServer(localHost, targetHost)
    var err error = nil*/
    http.HandleFunc("/", ServeHTTP)
   // 注释代码也可以在main中直接写,当然封装到方法中显得更加清晰
   /*
	   http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
	       if req.RequestURI == "/favicon.ico" {
	           io.WriteString(w, "Request path Error")
	           return
	       }
	       fmt.Println(req.RequestURI)
	       fmt.Fprintf(w, req.RequestURI)
	   })
*/
    http.ListenAndServe(":8085", nil)
}
 
func ServeHTTP(w http.ResponseWriter, r *http.Request) {
    if r.RequestURI == "/favicon.ico" {
        io.WriteString(w, "Request path Error")
        return
    }
    remote, err := url.Parse("http://" + "127.0.0.1:80")
    if err != nil {
        panic(err)
    }
    proxy := httputil.NewSingleHostReverseProxy(remote)
    proxy.ServeHTTP(w, r)
}

上述就是一个简单的代理功能实现,主要是通过httputil.NewSingleHostReverseProxy(targetUrl)
这个是httputil自带的方法,可以直接引用,但是如果我们想要做一个比较完整的反向代理功能那该怎么办呢?

需求:前端请求到后台,根据固定服务进行转发服务下的固定接口

分析:

如果已经知道是哪个具体的服务下的固定接口,那么我们可以比较简单的处理这种业务,比如我这里直接将这个接口完整请求路径作为代理转发后续path,那么只要前端请求的路径中包含这个固定path,当后端解析到有这个path,那么直接进入到这个代理转发功能上,代理功能根据请求地址后需要转发的服务域名(或者ip、端口)进行转发到这个服务上,然后根据path接口路径进行访问请求。这里需要注意:在进行访问服务下接口路径的时候,因为是转发到这个服务上,所以我们需要确定我们转发时将对应服务需要的鉴权认证信息携带过去(这里需要你明白具体服务是根据什么进行验权(token、cookie、或者直接用户信息在header中等等)),带上验证信息一起转发到服务中,这样,进行服务下接口访问的时候才能通过验权进行接口路径查询。

简单点说就是:比如这个path=/api/v1/user/ 这个路径就是user服务下的某个接口路径,我们统一路径,让前端给我们传递请求时候是:http://localhost:8080//api/v1/almsvr/ 这个路径到我们后台的时候,通过解析是否有/api/v1/almsvr/字段,如果有,就直接进入到代理转发功能,不再去走路由了,那么我们的代理转发功能直接实现具体业务就行了。

代码实现:

const (
	OriginHostReqHeader    = "X-Origin-Host"
	ForwardedHostReqHeader = "X-Forwarded-Host" // 代理路径,记录请求到底在中间经历了哪些代理
)
func forwardHttpRequest(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		/* 1. 这种是转发到固定的服务上的固定接口,如果前端请求是前缀包含/api/v1/user/getAllUer,则认为是需要进行转发用户服务查询*/
		if strings.HasPrefix(r.URL.Path, "/api/v1/user/getAllUer") { 
		 /* 
		这个方法直接给路径定死了,只要前端访问到/api/v1/user/getAllUer路径,就认为到用户服务,同时访问接口/api/v1/user/getAllUer,所以这里直接将r.URL.Path直接传下去,作为//director下path的路径了
		*/
			forwardUser(w, r, r.URL.Path)
			return
		}
		
		/*   2. 下面这个是可以转发到任意一个服务上上任意接口
			 可以考虑加一个固定path: serviceProxy/<serviceName>:<port>/<path>
			 比如:serviceProxy/ip:port/api/v1/ping
		*/
		if strings.HasPrefix(r.URL.Path, "/serviceProxy") {
			path := r.URL.Path[len("serviceProxy/")+1:]  
			forwardServiceProxy(w, r, path)
			return
		}
		next.ServeHTTP(w, r)
	})
}
// 转发到固定服务的固定方法代码实现
func forwardUser(w http.ResponseWriter, r *http.Request, rawPath string) {
	user:= config.Configuration.Clients["User"]  // 自己在配置文件中的服务名
	director := func(req *http.Request) {   // 最终要的,转发定向处理
		req.Header.Add(ForwardedHostReqHeader, req.Host)
		req.Header.Add(OriginHostReqHeader, user.Host)
		req.URL.Scheme = user.Protocol  // 协议
		req.URL.Host = fmt.Sprintf("%v:%v", user.Host, user.Port)  // 具体转发ip和端口
		req.URL.Path = rawPath  // 转发的服务具体接口路径  /api/v1/almsvr
		req.Method = r.Method   // 接口请求方法类型get、post、put、delete
	}

	errHandler := func(w http.ResponseWriter, r *http.Request, err error) {  // err处理
		if err != nil {
		 fmt.Sprint("failed to forward request, path =", rawPath))
			encodeErrorResponse(context.Background(), e, w) // 自己做一个错误返回处理
		}
	}

	resHandler := func(response *http.Response) error {   // 返回结果处理
		log.Debug("user http forward res: ", response)
		return nil
	}

	proxy := &httputil.ReverseProxy{Director: director, ModifyResponse: resHandler, ErrorHandler: errHandler}   // go自带反向代理方法
	proxy.Transport = &http.Transport{ResponseHeaderTimeout: time.Duration(user.Timeout) * time.Millisecond}
	proxy.ServeHTTP(w, r)   // http服务请求
}

上述代码中有一些我自己做的错误处理、配置文件读取等方法,你可以自己进行编写。
下面是任意服务下的代理转发

func forwardServiceProxy(w http.ResponseWriter, r *http.Request, rawPath string) {
	// rawPath= localhost:port/api/v1/ping
	index := strings.Index(rawPath, "/")
	if index == -1 {
		encodeErrorResponse(context.Background(), errors.ErrInternalServer, w)
		return
	}
	// localhost:port
	var host string
	var port int64
	var err error
	serviceAddr := rawPath[:index]
	split := strings.Split(serviceAddr, ":")
	if len(split) > 0 {
		host = split[0]
		port, err = strconv.ParseInt(split[1], 10, 64)
		// TODO 要加个返回具体错误信息方法 errors.ErrInternalServer
		if err != nil {
			encodeErrorResponse(context.Background(), errors.ErrInternalServer, w)
			return
		}
	}
	//  api/v1/ping
	apiUrl := rawPath[index:]
	director := func(req *http.Request) {
		req.Header.Add(ForwardedHostReqHeader, req.Host)
		req.Header.Add(OriginHostReqHeader, host)

		req.URL.Scheme = "http"    // 默认为http协议
		req.URL.Host = fmt.Sprintf("%v:%v", host, port)  // 具体服务的ip和端口  localhost:8085
		req.URL.Path = apiUrl   // api/v1/ping
		req.Method = r.Method   // get、post、delete、put
	}

	errHandler := func(w http.ResponseWriter, r *http.Request, err error) {
		if err != nil {
			e := errors.NewErrServerError(err, fmt.Sprint("failed to forward request, path =", rawPath))  // 自定义错误返回方法NewErrServerError
			encodeErrorResponse(context.Background(), e, w)
		}
	}

	resHandler := func(response *http.Response) error {
		log.Debug("serviceProxy http forward res: ", response)
		return nil
	}
	// 验证权限信息,加入到header中,带到转发服务下,进行校验,你应该按照你都项目中需要的方式进行信息验证
	/*
		添加自己转发服务需要的用户信息,放到上下文中进行下穿
		getUserInfo()
		...
	*/

	// go自带的反向代理方法,主要字段Director,这里面包含了代理需要的协议、服务ip端口、路径、请求方法
	proxy := &httputil.ReverseProxy{Director: director,  ModifyResponse: resHandler, ErrorHandler: errHandler}
	proxy.Transport = &http.Transport{ResponseHeaderTimeout: 5000 * time.Millisecond}  // 这个5000按照自己需求设定
	proxy.ServeHTTP(w, r)
}

以上就是具体的两种不同业务场景下的请求方式,相对还是比较完善的,大家有不懂的或者有什么改进、更好的办法的可以随时留言,希望能够同时进步。

Nginx是一个高性能的开源Web服务器,作为一个反向代理服务器,它可以接收客户端请求并将其转发给后端的服务器进行处理。而Golang是一种快速、高效且易于使用的编程语言,也被广泛用于开发网络应用。 使用Nginx和Golang进行反向代理可以带来许多好处。首先,Nginx作为反向代理服务器,具有负载均衡的能力,可以将客户端请求分发给多个后端服务器,从而提高系统的可靠性和可扩展性。同时,Nginx还能够缓存静态文件,减轻后端服务器的负担,提高系统的性能。 而Golang作为后端服务器的开发语言,具有并发执行的能力,可以处理大量的请求。它的编译速度非常快,且可以将应用程序编译成独立的二进制文件,无需依赖其他库。这意味着,我们可以方便地在多个服务器之间部署Golang应用程序,而不需要为每个服务器都安装Golang环境。 在实际使用中,我们可以将Nginx作为反向代理服务器,通过配置Nginx的代理规则,将客户端的请求转发给后端的Golang服务器。同时,可以通过Nginx的负载均衡策略,将请求分发给多个Golang服务器,以提高系统的可用性和性能。 总结来说,使用Nginx和Golang进行反向代理可以实现负载均衡、高可用性和高性能的网络应用。Nginx作为反向代理服务器能够高效地处理客户端请求,并将其转发给后端的Golang服务器进行处理。而Golang作为后端服务器的开发语言,具有并发执行和快速编译的优势,适合用于处理大量的请求。通过结合使用Nginx和Golang,我们可以构建出稳定、可靠且高性能的网络应用。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值