透传http请求遇到了一个小坑

本文讲述了如何在Go语言中使用gin-gonic/gin框架实现HTTP请求透传,同时指出`io.ReadAll(ctx.Request.Body)`可能导致请求体内容被消耗,影响后续请求处理的问题。
摘要由CSDN通过智能技术生成
package publicmessage

import (
	"bytes"
	"XXXXXX/global"   //本地项目封装的全局量,需要使用,换成自己封装的日志库即可
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"strings"

	"github.com/gin-gonic/gin"
)

// 透传http请求
func ProxyHandler(ctx *gin.Context) {
	var err error
	req := &http.Request{}
	defer func() {
		if err != nil {
			global.GIN_LOG.ErrorWithContext(ctx, err)
		}
	}()
	r := ctx.Request
	bodyBytes, _ := io.ReadAll(ctx.Request.Body)
	global.GIN_LOG.InfoWithContext(ctx, fmt.Sprintf("ProxyHandler method:%+v,url:%+v,body:%+v", r.Method, r.RequestURI, string(bodyBytes)))
	// 创建新的reader,使用bytes.NewReader
	bodyReader := bytes.NewReader(bodyBytes)
	// 恢复r.Body,以便可以多次读取
	r.Body = io.NopCloser(bodyReader)
	// 创建一个新的请求
	req, err = http.NewRequest(r.Method, r.RequestURI, r.Body)
	if err != nil {
		if ctx.Writer != nil {
			http.Error(ctx.Writer, err.Error(), http.StatusInternalServerError)
		}
		return
	}

	// 复制原始请求的Header
	for name, values := range r.Header {
		for _, value := range values {
			req.Header.Add(name, value)
		}
	}
	global.GIN_LOG.InfoWithContext(ctx, fmt.Sprintf("ProxyHandler request header:%+v", req.Header))

	// 发送请求到服务public_message
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		http.Error(ctx.Writer, err.Error(), http.StatusInternalServerError)
		return
	}
	defer resp.Body.Close()

    // 将服务public_message的响应头部写回到原始响应中
	for name, values := range resp.Header {
		for _, value := range values {
			ctx.Writer.Header().Add(name, value)
		}
	}


	// 将服务public_message的响应写回到原始响应中
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		http.Error(ctx.Writer, err.Error(), http.StatusInternalServerError)
		return
	}
	global.GIN_LOG.InfoWithContext(ctx, fmt.Sprintf("ProxyHandler response body:%+v", string(body)))
	ctx.Writer.Write(body)
}

这段代码我只是想做一下透传处理,把App端的http请求通过我的服务透传给另外一个服务,为了方便出了问题方便查询定位,我就把透传进来的http请求信息打印了一下,就是因为这个操作埋下了一个坑。在Go语言的HTTP处理中,io.ReadAll(ctx.Request.Body) 读取了请求体的全部内容,并将它存储在一个字节切片中。这个操作会消耗掉请求体的内容,因此,如果你尝试再次读取ctx.Request.Body,你会得到一个空的读取器(reader),因为数据已经被读取过了。

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值