侧边栏壁纸
  • 累计撰写 48 篇文章
  • 累计创建 7 个标签
  • 累计收到 2 条评论

目 录CONTENT

文章目录

【Golang】实现反向代理并修改请求参数和返回参数

Administrator
2023-05-11 / 0 评论 / 0 点赞 / 1 阅读 / 0 字

需求

用go实现一个反向代理服务。访问redmine系统的地址改为访问go新服务,go服务做代理并改写登录请求参数和返回参数。

原redmine地址:http://192.168.8.134 改为:http://127.0.0.1

分析

使用gin做http服务,使用net/http/httputil包进行代理

实现

package main

import (
    "fmt"
    "github.com/gin-gonic/gin"
    "io/ioutil"
    "net/http"
    "net/http/httputil"
    "net/url"
    "strconv"
    "strings"
)

func main() {
    //创建 gin 引擎
    g := gin.Default()
    //反向代理所有请求
    g.Use(proxyHandler)
    // 启动服务
    if err := g.Run(":80"); err != nil {
       panic(err)
    }
}

// api函数
func proxyHandler(c *gin.Context) {
    //反向代理的目的地址
    var target = "http://192.168.8.134"
    proxyURL, _ := url.Parse(target)

    reverseProxy := httputil.NewSingleHostReverseProxy(proxyURL)

    //req := c.Request
    //req.URL.Path = c.Param("path")
    originalDirector := reverseProxy.Director
    reverseProxy.Director = func(req *http.Request) {
       originalDirector(req)
       req.Host = proxyURL.Host
       req.URL.Scheme = proxyURL.Scheme
       req.URL.Host = proxyURL.Host
       if req.URL.Path == "/login" {
          // 针对登录接口,修改请求参数password对应的值
          if req.Method == "POST" && req.Header.Get("Content-Type") == "multipart/form-data" {
             err := req.ParseMultipartForm(0)
             if err != nil {
                panic(err)
             }
             req.MultipartForm.Value["password"] = []string{"12345678"}
          } else if req.Method == "POST" && req.Header.Get("Content-Type") == "application/x-www-form-urlencoded" {
             passwd, _ := c.GetPostForm("password")
             fmt.Println("========", passwd)
             req.Form = c.Request.Form
             //修改password为新的值
             req.Form.Set("password", "12345678")
             newBody := req.Form.Encode()
             req.ContentLength = int64(len(newBody))
             req.Body = ioutil.NopCloser(strings.NewReader(newBody))
             //修改长度
             req.Header.Set("Content-Length", strconv.Itoa(len(newBody)))
          }
       }

    }
    reverseProxy.ModifyResponse = func(resp *http.Response) error {
       resp.ContentLength = -1
       resp.Header.Set("Access-Control-Allow-Origin", "*")
       //修改重定向的地址
       resp.Header.Set("Location", "http://127.0.0.1:8080")
       return nil
    }
    reverseProxy.ServeHTTP(c.Writer, c.Request)
}

效果

原请求地址:

代理后的请求地址

登录成功后:

扩展为动态配置多个反向代理

package main

import (
    "fmt"
    "github.com/gin-gonic/gin"
    "io/ioutil"
    "net/http"
    "net/http/httputil"
    "net/url"
    "strconv"
    "strings"
)

func main() {
    // 创建 gin 引擎
    //engine := gin.Default()

    //go proxy(8081)
    go proxy(8080)

    g := gin.Default()
    g.Use(proxyHandler)
    //g.GET("a", func(context *gin.Context) {
    // p := context.Query("port")
    // fmt.Println("p", p)
    // pInt, _ := strconv.Atoi(p)
    // go proxy(pInt)
    // context.JSON(http.StatusOK, "ok")
    //})
    // 启动服务
    if err := g.Run(":80"); err != nil {
       panic(err)
    }
}
func proxy(port int) {
    engine := gin.Default()
    // router路由
    engine.Use(proxyHandler)

    // 启动服务
    if err := engine.Run(":" + strconv.Itoa(port)); err != nil {
       panic(err)
    }
}

// api函数
func proxyHandler(c *gin.Context) {

    var target = "http://192.168.8.134"
    proxyURL, _ := url.Parse(target)

    reverseProxy := httputil.NewSingleHostReverseProxy(proxyURL)

    //req := c.Request
    //req.URL.Path = c.Param("path")
    originalDirector := reverseProxy.Director
    reverseProxy.Director = func(req *http.Request) {
       originalDirector(req)
       req.Host = proxyURL.Host
       req.URL.Scheme = proxyURL.Scheme
       req.URL.Host = proxyURL.Host
       fmt.Println("path====", req.URL.Path)
       // 修改请求参数
       if req.Method == "POST" && req.Header.Get("Content-Type") == "multipart/form-data" {
          err := req.ParseMultipartForm(0)
          if err != nil {
             panic(err)
          }
          req.MultipartForm.Value["password"] = []string{"12345678"}
       } else if req.Method == "POST" && req.Header.Get("Content-Type") == "application/x-www-form-urlencoded" {
          pass, _ := c.GetPostForm("password")
          fmt.Println("========", pass)
          req.Form = c.Request.Form
          req.Form.Set("password", "12345678")
          //req.Form.Set("utf8", "✓")
          //req.Form.Set("back_url", "/")
          //req.Form.Set("login", "登录")
          //req.Form.Set("authenticity_token", token)
          newBody := req.Form.Encode()
          req.ContentLength = int64(len(newBody))
          req.Body = ioutil.NopCloser(strings.NewReader(newBody))
          req.Header.Set("Content-Length", strconv.Itoa(len(newBody)))
       }

       //b, _ := ioutil.ReadAll(req.Body)
       //fmt.Println("body", string(b))
    }
    reverseProxy.ModifyResponse = func(resp *http.Response) error {
       resp.ContentLength = -1
       resp.Header.Set("Access-Control-Allow-Origin", "*")
       resp.Header.Set("Location", "http://127.0.0.1:8080")
       return nil
    }
    //reverseProxy.ServeHTTP(c.Writer, req)
    reverseProxy.ServeHTTP(c.Writer, c.Request)
}

0

评论区