Golang使用ReverseProxy实现反向代理

news2024/9/20 20:40:38

目录

1.源码结构体 

2.官方单机示例

3.使用示例

4.简单的http服务(用于测试)


1.源码结构体 

type ReverseProxy struct {

    // Rewrite 必须是一个函数,用于将请求修改为要使用 Transport 发送的新请求。然后,其响应将原封不动地复制回原始客户端。返回后,Rewrite 不得访问提供的 ProxyRequest 或其内容。
    // 在调用 Rewrite 之前,将从出站请求中删除 Forwarded、X-Forwarded、X-Forwarded-Host 和 X-Forwarded-Proto 标头。另请参阅 ProxyRequest.SetXForwarded 方法。
    // 在调用 Rewrite 之前,将从出站请求中删除不可解析的查询参数。Rewrite 函数可以将入站 URL 的 RawQuery 复制到出站 URL 以保留原始参数字符串。请注意,如果代理对查询参数的解释与下游服务器的解释不匹配,这可能会导致安全问题。
    // 最多可以设置 Rewrite 或 Director 中的一个。
    Rewrite func(*ProxyRequest)

    // Director 是一种将请求修改为要使用 Transport 发送的新请求的功能。然后,其响应将原封不动地复制回原始客户端。Director 在返回后不得访问提供的请求。
    //默认情况下,X-Forwarded-For 标头设置为客户端 IP 地址的值。如果 X-Forwarded-For 标头已存在,则客户端 IP 将附加到现有值。作为特殊情况,如果标头存在于 Request.Header 映射中,但具有 nil 值(例如由 Director func 设置时),则不会修改 X-Forwarded-For 标头。
    // 为防止 IP 欺骗,请务必删除来自客户端或不受信任的代理的任何预先存在的 X-Forwarded-For 标头。
    // 在 Director 返回后,将从请求中删除逐跳标头,这可以删除 Director 添加的标头。请改用 Rewrite 函数来确保保留对请求的修改。
    // 如果在 Director 返回后设置 Request.Form,则会从出站请求中删除不可解析的查询参数。
    // 最多可以设置 Rewrite 或 Director 中的一个。
    Director func(*http.Request)

    // 用于执行代理请求的传输。如果为 nil,则使用为 http.DefaultTransport
    Transport http.RoundTripper

    // FlushInterval 指定在复制响应正文时要刷新到客户端的刷新间隔。如果为零,则不执行定期刷新。负值表示在每次写入 Client 端后立即刷新。当 ReverseProxy 将响应识别为流式响应或其 ContentLength 为 -1 时,将忽略 FlushInterval;对于此类响应,写入会立即刷新到客户端。
    FlushInterval time.Duration

    // ErrorLog 为尝试代理请求时发生的错误指定可选记录器。如果为 nil,则通过 log 包的标准 logger 完成日志记录。
    ErrorLog *log.Logger

    // BufferPool 可以选择指定一个缓冲池,以获取 io 使用的字节切片。CopyBuffer 在复制 HTTP 响应正文时。   
    BufferPool BufferPool

    // ModifyResponse 是一个可选函数,用于修改来自后端的 Response。如果后端返回带有任何 HTTP 状态代码的响应,则调用它。如果无法访问后端,则调用可选的 ErrorHandler,而不调用 ModifyResponse。如果 ModifyResponse 返回错误,则调用 ErrorHandler 及其错误值。如果 ErrorHandler 为 nil,则使用其默认实现。
    ModifyResponse func(*http.Response) error

    // ErrorHandler 是一个可选函数,用于处理到达后端的错误或来自 ModifyResponse 的错误。如果为 nil,则默认记录提供的错误并返回 502 Status Bad Gateway 响应。    
    ErrorHandler func(http.ResponseWriter, *http.Request, error)
}

2.官方单机示例

NewSingleHostReverseProxy是官方给的示例,代理单机服务,如果想实现负载均衡,需自己实现。

源码:

3.使用示例

package main

import (
	"log"
	"net"
	"net/http"
	"net/http/httputil"
	"net/url"
	"os"
	"sync"
	"time"
)

// 从Go 1.18版本开始,httputil.ReverseProxy 的 BufferPool 字段期望的是一个实现了 BufferPool 接口的对象,该接口要求有一个返回 []byte 的 Get 方法和一个接受 []byte 的 Put 方法。
// 定义一个实现了 BufferPool 接口的结构体
// 定义一个实现了 BufferPool 接口的结构体
type byteBufferPool struct {
	sync.Pool
}

// 实现 BufferPool 接口的 Get 方法
func (b *byteBufferPool) Get() []byte {
	v := b.Pool.Get()
	if v == nil {
		return make([]byte, 1024*1024) // 分配 1MB 的缓冲区
	}
	return v.([]byte)
}

// 实现 BufferPool 接口的 Put 方法
func (b *byteBufferPool) Put(bts []byte) {
	b.Pool.Put(bts)
}

// 定义一个实现了 ErrorHandler 接口的函数
func customErrorHandler(w http.ResponseWriter, r *http.Request, err error) {
	// 记录错误
	log.Printf("Error occurred: %v", err)

	// 返回自定义的状态码和错误消息
	w.WriteHeader(http.StatusInternalServerError)
	w.Write([]byte("An internal error occurred."))
}

func main() {
	// 目标服务器的 URL
	targetURL := "http://localhost:8081"

	// 解析目标 URL
	target, err := url.Parse(targetURL)
	if err != nil {
		log.Fatalf("Failed to parse target URL: %v", err)
	}

	// 创建反向代理
	proxy := httputil.NewSingleHostReverseProxy(target)

	// 设置 FlushInterval
	// FlushInterval 是一个 time.Duration 类型的字段,它指定了代理服务器将缓冲的数据写入客户端的间隔时间。这对于实现实时应用(如实时聊天、日志流等)非常重要,因为它可以减少延迟,让客户端更快地接收到数据。
	proxy.FlushInterval = 100 * time.Millisecond

	// 设置反向代理的 Transport
	proxy.Transport = &http.Transport{
		DialContext: (&net.Dialer{
			Timeout:   30 * time.Second, // 建立连接的最大等待时间
			KeepAlive: 30 * time.Second, // 保持连接活跃的时间间隔
			DualStack: true,             // 尝试同时使用 IPv4 和 IPv6 地址
		}).DialContext,
		MaxIdleConns:          100,              // 最大空闲连接数
		IdleConnTimeout:       90 * time.Second, // 空闲连接超时时间
		TLSHandshakeTimeout:   10 * time.Second, // TLS握手超时时间
		ExpectContinueTimeout: 1 * time.Second,  // Expect: 100-continue 超时时间
	}

	// 创建自定义的日志器
	proxy.ErrorLog = log.New(os.Stderr, "ERROR: ", log.LstdFlags)

	// 设置反向代理的 BufferPool 缓冲池
	proxy.BufferPool = &byteBufferPool{
		Pool: sync.Pool{
			New: func() interface{} {
				return make([]byte, 1024*1024) // 分配 1MB 的缓冲区
			},
		},
	}

	// 设置反向代理的 ModifyResponse
	proxy.ModifyResponse = func(res *http.Response) error {
		// 修改响应头
		res.Header.Set("X-Modified-By", "ReverseProxy")
		// 修改状态码(示例)
		res.StatusCode = 200
		// 返回 nil 表示继续处理
		return nil
	}

	// 设置反向代理的 ErrorHandler
	proxy.ErrorHandler = customErrorHandler

	// 创建 HTTP 服务器
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		// 调用反向代理
		proxy.ServeHTTP(w, r)
	})

	// 启动 HTTP 服务器
	log.Println("Starting server on :8080")
	log.Fatal(http.ListenAndServe(":8080", nil))
}

4.简单的http服务(用于测试)

package main

import (
	"fmt"
	"log"
	"net/http"
)

func helloWorldHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hello, World!")
}

func main() {
	http.HandleFunc("/", helloWorldHandler)

	log.Println("Starting server on :8081")
	log.Fatal(http.ListenAndServe(":8081", nil))
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2132260.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

打造古风炫酷个人网页:用HTML和CSS3传递笔墨韵味

需要用到的背景大家可以自己找喜欢的风格!!! 当然俺把俺用的背景放到文章最后了哦!!!!! 感谢关注和支持 长期更新哦~~~ 1. 简洁的页面布局:保持优雅和对称 在古风设计中,布局的对称性非常重要…

【知识图谱】3.Protege下载安装

一、Protege 1.相关介绍 Protg软件是斯坦福大学医学院生物信息研究中心基于Java语言开发的本体编辑和知识获取软件,或者说是本体开发工具,也是基于知识的编辑器,属于开放源代码软件。 这个软件主要用于语义网中本体的构建,是语义…

第15-02章:理解Class类并获取Class实例

我的后端学习大纲 我的Java学习大纲 1、Java反射机制原理图: 源代码通过Javac编译得到字节码文件,当我执行到new一个对象的时候,字节码文件会通过ClassLoader被加载,然后得到一个Class类对象,存放在堆中,加…

系统分析师10:知识产权与标准化

1 内容提要 保护范围与对象(★★★★)保护期限(★)知识产权人确定(★★★)侵权判断(★★★)标准的分类标准代号的识别 2 保护范围与对象 使用许可 按照被许可使用权的排他性强弱不同,可以将使用许可分为以下三种: ①独占使用许可-仅1个授权…

中国电子学会202406青少年软件编程(Python)等级考试试卷(一级)真题与解析

青少年软件编程(Python)等级考试试卷(一级) 分数:100题数:37 一、单选题(共25题,共50分) 1.在使用turtle绘制图形时,如果要控制小海龟移动到 x 坐标为 200,y 坐标为150 的位置,以下代码能够实现效果的是?( ) A. turtle.go(150, 200) B. turtle.go(200, 150) …

在线客服如何与呼叫系统结合使用?

以下是在线客服与呼叫系统结合使用的常见方式: 1.从客户接入角度 a多渠道整合: 将网站在线客服、手机APP在线客服、社交媒体平台(如微信公众号、微博私信等)以及呼叫系统的电话接入渠道整合在一个统一的平台上。例如&#xf…

HTTP跨域请求时为什么要发送options请求

跨域请求 浏览器同源策略同源策略一般限制Ajax网络请求&#xff0c;不能跨域请求server不会限制<link> <img> <script> <iframe> 加载第三方资源 JSONP实现跨域 <!-- aa.com网页 --> <script>window.onSuccess function(data) {consol…

如何选择PCB板材?

pcb板材的基本参数有哪些&#xff1f; 1. 厚度&#xff1a;PCB板材厚度是指板子的整体厚度。常见的厚度有0.8mm、1.0mm、1.6mm、2.0mm等。在选择时需要根据实际需求进行选择&#xff0c;通常需要根据元件数量、限制空间和性能要求来决定。 2. 热膨胀系数&#xff1a;热膨胀系数…

把设计模式用起来(3)用不好的原因之时机不对

上一篇&#xff1a;《把设计模式用起来&#xff08;3&#xff09;——用不好的原因 之 实践不足》https://blog.csdn.net/nanyu/article/details/141939342 本篇继续讲设计模式用不好的常见原因&#xff0c;这是第二个&#xff1a;使用设计模式的时机不对。 二、时机不对 这里…

linux的文本编辑器vim常用操作命令介绍

目录 一、vim介绍 二、vim的特点 1、模式编辑 2、强大的命令集 3、可配置性 4、插件系统 5、多平台支持 三、vim的基础用法 1、打开或创建文件 2、移动光标 3、编辑文件 4、返回命令模式 5、保存文件并退出 6、不保存并退出 四、vim的部分进阶用法 1、快速删除行 2、撤销操作…

数据结构——复杂度讲解

已经太久没用更新了&#xff0c;由于各种原因&#xff0c;导致很久没用更新了&#xff0c;但是停更期间我也是一直在很努力的学习与复习之前学过的知识&#xff0c;读了两本C语言的数据&#xff0c;初学者也是可以看的&#xff0c;推荐给大家&#xff0c;如果需要pdf&#xff0…

SAP TR传输工具

实现效果 不用释放请求&#xff0c;可以把对方对象从DEV直接释放到目标系统中 表对象设计 表结构设计 1. ZSAB0007 Develop toolset: current working objects 2. Structure&#xff1a;ZSAB0008 发版计划请求列表 3. ZSAB0022 Development objects - object search r…

Bootstrap布局实例(偏移列)

偏移是一个用于更专业的布局的有用功能。它们可用来给列腾出更多的空间。例如&#xff0c;.col-xs-* 类不支持偏移&#xff0c;但是它们可以简单地通过使用一个空的单元格来实现该效果。 为了在大屏幕显示器上使用偏移&#xff0c;请使用 .col-md-offset-* 类。这些类会把一个…

Vue3: setup语法糖

一. setup语法糖 在 Vue 3 中&#xff0c;setup 语法糖是一种简化组件内部状态和方法管理的特性。它允许你将组件的逻辑直接编写在组件的定义中&#xff0c;而不是像 Vue 2 那样需要在 methods 和 data 属性中管理。setup 语法糖基于 ES6 的类的静态方法&#xff0c;允许你更灵…

改进大语言模型的最全方法!

这是一篇关于适应开源大语言模型&#xff08;LLMs&#xff09;的三部系列博客的第一篇。本文探讨将LLM适应领域数据的各种方法。 第二部分讨论如何确定微调&#xff08;fine-tuning&#xff09;是否适合您的用例。第三部分探讨策划良好训练数据集的一些经验法则。 0 引言 大…

NX二次开发—批量导出点工具

在NX上进行二次开发&#xff0c;设计一个UI界面&#xff0c;将选择的点导出 在NX上&#xff0c;进行UI样式编辑器 添加选择对象&#xff0c;修改标题&#xff0c;设置为多选 创建一个组&#xff0c;添加枚举&#xff0c;设置标题和枚举内容&#xff0c;不显示枚举标题LabelVis…

云微客AI文案编写,有手就能出“爆款”

​现如今新媒体时代&#xff0c;短视频平台已经成为了企业品牌宣传的重要战场&#xff0c;那么如何利用短视频平台进行品牌宣传、制作爆款视频就成为了各大商企需要解决的难题。由此&#xff0c;不得不提到云微客短视频矩阵系统&#xff0c;一键助力商企品牌轻松打造爆款内容。…

python学习第九节:爬虫实战-抓取地址库

python学习第九节&#xff1a;爬虫实战-抓取地址库 话不多说&#xff0c;直接上代码&#xff1b;下面的代码是从统计局抓取地址库并保存为json格式和excel格式。大家拿到代码直接运行即可。 #codingutf-8 #加入上面这行代码表示可以在下面代码中包含中文 import bs4 #网页解析…

wopop靶场漏洞挖掘练习

一、sql注入漏洞 1.在搜索框输入-1 union select 1,2,3# 可以看到页面有回显 2.查询数据库名 -1 union select 1,2,database()# 3.通过查询admin表的数据可以进行登录后台 -1 union select 1,2,group_concat(user_name,user_pass) from admin# 二、文件上传漏洞 1.登录后台…

李龙受邀参加济南高新区“质量月”能力提升活动,并做专题培训

9月11日&#xff0c;济南高新区在山东省知识产权公共服务平台举行2024年“质量月”启动仪式暨质量管理能力提升系列活动。安畅检测首席技术专家李龙先生出席了“质量月”启动仪式 &#xff0c;并为到场企业代表就信创产业相关知识做了专题培训。 济南市市场监督管理局党组成员王…