go语言 反向代理

news2024/9/28 23:28:23

实现简单的http反向代理 还没有加入负载均衡 新手推荐

下游服务器代码

package main

import (
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"
)

type RealServer struct {
	Addr string
}

func (r *RealServer) Run() {
	log.Println("Starting httpserver at " + r.Addr)
	mux := http.NewServeMux()
	mux.HandleFunc("/", r.HelloHandler)
	mux.HandleFunc("/base/error", r.ErrorHandler)
	mux.HandleFunc("/test_http_string/test_http_string/aaa", r.TimeoutHandler)
	server := &http.Server{
		Addr:         r.Addr,
		WriteTimeout: time.Second * 3,
		Handler:      mux,
	}
	go func() {
		log.Fatal(server.ListenAndServe())
	}()
}

func (r *RealServer) HelloHandler(w http.ResponseWriter, req *http.Request) {

	upath := fmt.Sprintf("http://%s%s\n", r.Addr, req.URL.Path)
	realIP := fmt.Sprintf("RemoteAddr=%s,X-Forwarded-For=%v,X-Real-Ip=%v\n", req.RemoteAddr, req.Header.Get("X-Forwarded-For"), req.Header.Get("X-Real-Ip"))
	header := fmt.Sprintf("headers =%v\n", req.Header)
	io.WriteString(w, upath)
	io.WriteString(w, realIP)
	io.WriteString(w, header)

}

func (r *RealServer) ErrorHandler(w http.ResponseWriter, req *http.Request) {
	upath := "error handler"
	w.WriteHeader(500)
	io.WriteString(w, upath)
}

func (r *RealServer) TimeoutHandler(w http.ResponseWriter, req *http.Request) {
	time.Sleep(6 * time.Second)
	upath := "timeout handler"
	w.WriteHeader(200)
	io.WriteString(w, upath)
}

func main() {
	rs1 := &RealServer{Addr: "127.0.0.1:2003"}
	rs1.Run()
	rs2 := &RealServer{Addr: "127.0.0.1:2004"}
	rs2.Run()

	//监听关闭信号
	quit := make(chan os.Signal)
	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
	<-quit
}

反向代理代码

主要的思路是拿到httputil.ReverseProxy,修改里面内置的一些方法
该结构体有ServeHttp接口 因此可以直接使用到funhandlc中

package main

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/http/httputil"
	"net/url"
	"regexp"
	"strings"
)

// 当前服务器地址
var addr = "127.0.0.1:2222"

func main() {

	//设置下游的地址
	rs1 := "http://127.0.0.1:2003"
	url1, err := url.Parse(rs1)
	if err != nil {
		log.Println(err)
	}

	proxy := NewSingleHostReverseProxy(url1)
	log.Println("Starting httpserver at " + addr)
	log.Fatal(http.ListenAndServe(addr, proxy))
}

func NewSingleHostReverseProxy(target *url.URL) *httputil.ReverseProxy {
	targetQuery := target.RawQuery

	//设置新的请求信息
	director := func(req *http.Request) {
		//url_rewrite
		//127.0.0.1:2002/dir/abc ==> 127.0.0.1:2003/base/abc ??
		//127.0.0.1:2002/dir/abc ==> 127.0.0.1:2002/abc
		//127.0.0.1:2002/abc ==> 127.0.0.1:2003/base/abc
		re, _ := regexp.Compile("^/dir(.*)")
		req.URL.Path = re.ReplaceAllString(req.URL.Path, "$1")

		req.URL.Scheme = target.Scheme
		req.URL.Host = target.Host

		//target.Path : /base
		//req.URL.Path : /dir
		req.URL.Path = singleJoiningSlash(target.Path, req.URL.Path)
		if targetQuery == "" || req.URL.RawQuery == "" {
			req.URL.RawQuery = targetQuery + req.URL.RawQuery
		} else {
			req.URL.RawQuery = targetQuery + "&" + req.URL.RawQuery
		}
		if _, ok := req.Header["User-Agent"]; !ok {
			req.Header.Set("User-Agent", "")
		}
	}

	//修改返回值
	modifyFunc := func(res *http.Response) error {
		if res.StatusCode != 200 {
			return errors.New("error statusCode")

		}
		oldPayload, err := io.ReadAll(res.Body)
		if err != nil {
			return err
		}
		newPayLoad := []byte("hello " + string(oldPayload))
		res.Body = io.NopCloser(bytes.NewBuffer(newPayLoad))
		res.ContentLength = int64(len(newPayLoad))
		res.Header.Set("Content-Length", fmt.Sprint(len(newPayLoad)))
		return nil
	}
	//错误处理
	errorHandler := func(res http.ResponseWriter, req *http.Request, err error) {
		res.Write([]byte(err.Error()))
	}
	return &httputil.ReverseProxy{Director: director, ModifyResponse: modifyFunc, ErrorHandler: errorHandler}
}

// 重新组合URL
func singleJoiningSlash(a, b string) string {
	aslash := strings.HasSuffix(a, "/")
	bslash := strings.HasPrefix(b, "/")
	switch {
	case aslash && bslash:
		return a + b[1:]
	case !aslash && !bslash:
		return a + "/" + b
	}
	return a + b
}

通过反向代理修改返回结果 添加了hello

oldPayload, err := io.ReadAll(res.Body)
		if err != nil {
			return err
		}
		newPayLoad := []byte("hello " + string(oldPayload))
		res.Body = io.NopCloser(bytes.NewBuffer(newPayLoad))
		res.ContentLength = int64(len(newPayLoad))
		res.Header.Set("Content-Length", fmt.Sprint(len(newPayLoad)))

在这里插入图片描述

X-Forwarded-For 头部

记录整个代理过程的IP
可能会被仿造 也就是发送请求的时候改变X-Forwarded-For的内容
在这里插入图片描述

X-Real-IP 头部

拿到请求的真实服务器的IP
每次代理都会被覆盖,只需要在第一层代理设置转发
不会被伪造
在这里插入图片描述

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

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

相关文章

uniapp解决scroll滑动之后被u-sticky挡住的问题

问题&#xff1a;页面触底加载之后&#xff0c;回到头部&#xff0c;顶部数据被遮挡 将<swiper class"swiper-list"></swiper>上的swiper-list样式高度调整成90vh <view class"main"><u-sticky bgColor"#fff"><u-…

PRT(Precomputed Radiance Transfer【2002】)原理实现

声明 本文源自对Games202课程&#xff0c;作业2的总结。 参考 手把手教你写GAMES202作业&#xff1a;GAMES202-作业2&#xff1a; Precomputed Radiance Transfer&#xff08;球谐函数&#xff09;GAMES 202 作业2Games202课程个人Blog 课程总结&#xff1a;Games202(P6、P7…

C++ - 异常介绍和使用

前言 我们在日常编写代码的时候&#xff0c;难免会出现编写错误带来程序的奔溃&#xff0c;或者是用户在使用我们编写的程序时候&#xff0c;使用错误所带来程序的奔溃。 在C 当中 可以对你觉得可能发生 错误 的地方在运行之前进行判断&#xff0c;发生错误可以给出提示。 C…

JOSEF约瑟 智能电流继电器KWJL-20/L KWLD26 零序孔径45mm 柜内导轨式安装

KWJL-20智能电流继电器 零序互感器&#xff1a; KWLD80 KWLD45 KWLD26 KWJL-20 一、产品概述 KWJL-20系列智能剩余电流继电器&#xff08;以下简称继电器&#xff09;适用于交流电压至660V或更高的TN、TT、和IT系统&#xff0c;频率为50Hz。通过零序电流互感器检测出超过…

TS编译器选项compilerOptions指定编译ES版本和模块化使用规范

compilerOptions是TS的编译器选项&#xff0c;主要在tsconfig.json文件中用于对ts编译为js文件时进行配置 "compilerOptions" : { 配置项 } 一、target指定ts被编译的ES版本 {// compilerOptions 编译器选项"compilerOptions": {// target 用来指定ts被编…

寻找AI-Native创业者

亲爱的科技探险家们和代码魔法师们&#xff1a; 未来的钟声已经敲响&#xff0c;预示着一场极度炫酷的虚拟现实游戏即将展开。从初期简单的智能识别&#xff0c;到设计师级别的图纸设计&#xff0c;生成式AI技术&#xff08;Generative AI&#xff09;以其独特理念和创新模式重…

基于springboot+vue的在线购房(房屋租赁)系统

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…

Java21的新特性

Java语言特性系列 Java5的新特性Java6的新特性Java7的新特性Java8的新特性Java9的新特性Java10的新特性Java11的新特性Java12的新特性Java13的新特性Java14的新特性Java15的新特性Java16的新特性Java17的新特性Java18的新特性Java19的新特性Java20的新特性Java21的新特性Java22…

Java下打印直角三角型(另一个方向)

代码如下&#xff1a; public class MyWork {public static void main(String[] args) {int num 5;for (int i 0; i < num; i) {for (int j 0; j < i; j) {System.out.print("-");}for (int j 0; j < num - i; j) {System.out.print("*");}S…

Ubuntu 安装 CUDA 与 OPENCL

前言&#xff1a;最近需要做一些GPU并行计算&#xff0c;因而入坑CUDA和OPENCL&#xff0c;两者都有用到一些&#xff0c;刚好有点时间&#xff0c;同时记录一些学习过程&#xff0c;排掉一些坑&#xff0c;这篇是环境安装篇&#xff0c;基本跟着走就没什么问题&#xff0c;环境…

字节跳动大规模多云CDN管理与产品化实践

近日&#xff0c;火山引擎边缘云融合CDN团队负责人孙益星在LiveVideoStack Con 2023上海站围绕融合CDN团队持续建设多云CDN平台的演进过程&#xff0c;结合建设过程中面临的难点和挑战&#xff0c;介绍了融合CDN团队接下来的主要投入方向&#xff0c;分享了火山引擎在多云应用架…

tp5.1 致命错误: Call to undefined method think\Cache::get()

致命错误: 致命错误: Call to undefined method think\Cache::get() 原因&#xff1a;&#xff08;引用类错误&#xff09; thinkphp5.1中有两个Cache类&#xff1a;think\Cache和think\facade\Cache。 官方文档中说使用think\Cache&#xff0c;但实际是使用think\facade\Cac…

SQL Server数据库中了360后缀勒索病毒怎么办,勒索病毒解密数据恢复

随着互联网的发展&#xff0c;网络安全问题日益凸显&#xff0c;勒索病毒已经成为当今数字威胁中的一大主要犯罪行为之一。其中&#xff0c;360后缀勒索病毒作为一种常见的数据库攻击形式&#xff0c;对数据库的安全性提出了极大挑战。近期我们收到很多企业的求助&#xff0c;企…

RocketMQ 源码分析——NameServer

文章目录 为什么要学RocketMQ源码RocketMQ源码中的技术亮点RocketMQ 模块结构NameServer 源码分析NameServer 整体流程NameServer 启动流程加载KV配置构建NRS通讯接收路由、心跳信息定时任务剔除超时Broker NameServer设计亮点读写锁存储基于内存NameServer无状态化 为什么要学…

SpringIOC之Lifecycle 接口

博主介绍&#xff1a;✌全网粉丝4W&#xff0c;全栈开发工程师&#xff0c;从事多年软件开发&#xff0c;在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战&#xff0c;博主也曾写过优秀论文&#xff0c;查重率极低&#xff0c;在这方面有丰富的经验…

计算机等级考试信息安全三级填空题-二

1.信息安全的五个根本属性是&#xff1a;机密性、完整性可控性、不可否认性和完整性。 2.在Windows系统中&#xff0c;查看当前已经启动的效劳列表的命令是&#xff1a;net start 3.在数据库中&#xff0c;删除表的命令是&#xff1a;DROP 4.在信息资产治理中&#xff0c;标准…

zabbix的原理与安装

一、Zabbix介绍 1、zabbix 是什么&#xff1f; zabbix是一个开源的IT基础监控软件&#xff0c;能实时监控网络服务&#xff0c;服务器和网络设备的状态&#xff0c;如网络使用&#xff0c;CPU负载、磁盘空间等&#xff0c;主要是包括数据的收集、报警和通知的可视化界面zabbi…

Java下打印1-100以内的质数

代码如下&#xff1a; public class MyWork {public static void main(String[] args) {System.out.println("100以内的质数如下&#xff1a;");for (int num 0; num < 100; num) {if (2 num) {System.out.print(num " ");continue;}for (int i 2;…

晚上弱光拍照不够清晰,学会这几招画面清晰效果好

很多小伙伴喜欢夜晚拍摄&#xff0c;然而拍摄出来的照片经常画面偏暗甚至模糊不清&#xff0c;这是怎么回事&#xff1f; 弱光环境是很多人都比较头疼的拍摄场合&#xff0c;由于光线弱曝光不好把控&#xff0c;并且还很容易出现细节性问题&#xff0c;想要将照片拍好就非常不…

全网最详细的自动化测试(Jenkins 篇)

学习 Jenkins 自动化测试的系列文章 Robot Framework 概念Robot Framework 安装Pycharm Robot Framework 环境搭建Robot Framework 介绍Jenkins 自动化测试 1. Robot Framework 概念 Robot Framework是一个基于Python的&#xff0c;可扩展的关键字驱动的自动化测试框架。 …