golang 超简单实现反向代理(nginx 端口转发 Proxy)

100行你就可以做到类似nginx带自动更新的端口转发功能

总共就2个文件,一个main(总行数128行),一个配置文件

main:

里面的json解析和log可以忽略

package main

import (
	"github.com/weimingjue/json"
	utils2 "goProxy/utils"
	"goService/utils"
	"io/ioutil"
	"net"
	"net/http"
	"net/http/httputil"
	"net/url"
	"os"
	"strings"
	"sync"
	"time"
)

var (
	projectDir, _         = os.Getwd()
	fileName              = projectDir + "/domain.config"
	readFileTime    int64 = 0  //读取文件的时间
	fileChangedTime int64 = 0  //文件修改时间
	domainData      [][]string //[{***.gq,8080,http://127.0.0.1:8080/}]
	duPeiZhiSuo     sync.Mutex //读配置锁
)

// 获取反向代理域名
func getProxyUrl(reqDomain string) string {
	checkFile()

	for _, dms := range domainData {
		if strings.Index(reqDomain, dms[0]) >= 0 {
			return dms[2]
		}
	}
	return domainData[0][2]
}

//读取配置文件
//域名:端口号,未知域名默认用第一个
func checkFile() {
	nowTime := time.Now().Unix()
	if nowTime-readFileTime < 300 {
		return
	}
	//每5分钟判断文件是否修改
	domainFile, _ := os.OpenFile(fileName, os.O_WRONLY|os.O_APPEND, 0)
	info, _ := domainFile.Stat()
	if info.ModTime().Unix() == fileChangedTime {
		return
	}
	duPeiZhiSuo.Lock()
	defer duPeiZhiSuo.Unlock()
	domainFile, _ = os.OpenFile(fileName, os.O_WRONLY|os.O_APPEND, 0) //加锁再来一遍,防止重入
	info, _ = domainFile.Stat()
	changedTime := info.ModTime().Unix()
	if changedTime == fileChangedTime {
		return
	}

	//文件改变

	//重置数据
	readFileTime = nowTime
	fileChangedTime = changedTime
	domainData = [][]string{}

	bytes, _ := ioutil.ReadFile(fileName)
	split := strings.Split(string(bytes), "\n")

	for _, domainInfo := range split {
		dLen := len(domainInfo)
		if dLen < 8 || dLen > 20 { //忽略错误信息
			continue
		}
		domainItems := strings.Split(domainInfo, ":")
		if len(domainItems) != 2 || len(domainItems[0]) < 3 || len(domainItems[1]) < 2 {
			continue
		}
		if utils.EndWidth(domainItems[1], "/") {
			domainItems = append(domainItems, "http://127.0.0.1:"+domainItems[1])
		} else {
			domainItems = append(domainItems, "http://127.0.0.1:"+domainItems[1]+"/")
		}
		domainData = append(domainData, domainItems)
	}

	domainSt, _ := json.Marshal(domainData)
	utils2.MyLogProxyI("配置已修改:" + string(domainSt))
}

//获取主机名
func getHost(req *http.Request) string {
	if req.Host != "" {
		if hostPart, _, err := net.SplitHostPort(req.Host); err == nil {
			return hostPart
		}
		return req.Host
	}
	return "localhost"
}

func handleRequestAndRedirect(res http.ResponseWriter, req *http.Request) {
	host := getHost(req)
	proxyUrl := getProxyUrl(host)
	url2, _ := url.Parse(proxyUrl)
	utils2.MyLogProxyI("请求域名:" + host + ",转到:" + proxyUrl)

	// create the reverse proxy
	proxy := httputil.NewSingleHostReverseProxy(url2)

	// Update the headers to allow for SSL redirection
	req.URL.Host = url2.Host
	req.URL.Scheme = url2.Scheme
	req.Header.Set("X-Forwarded-Host", req.Header.Get("Host"))
	req.Host = url2.Host

	// Note that ServeHttp is non blocking and uses a go routine under the hood
	proxy.ServeHTTP(res, req)
}

func main() {
	http.HandleFunc("/", handleRequestAndRedirect)
	if err := http.ListenAndServe(":80", nil); err != nil {
		utils.MyLogE("Proxy监听80端口错误:" + err.Error())
		panic(err)
	}
}

domain.config:

***为自己的域名,":"后面是需要转发的端口,不用写http://,任何地方都不能有空格

wang.gq:8080
***.aa:8081/

代码写的是相对目录请到当前目录执行"go run main.go",愉快的转发从现在开始

参考资料(抄的😂):https://studygolang.com/articles/14246

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值