简单记录一下我实现的过程和遇到的一些问题
加载配置文件
配置文件内容:
./config.json
{
"www.test1.com": "https://www.baidu.com",
"www.test2.com": "https://www.sina.com.cn"
}将文件内容加载,放入data ,并且存放在ProxyTarget这个map[string]string中
type ProxyTarget map[string]string
// loadConfig 加载配置文件
func loadConfig(configFile string) error {
data, err := ioutil.ReadFile(configFile)
if err != nil {
return err
}
return json.Unmarshal(data, &ProxyConfig)
}使用到了json.Unmarshal函数,函数签名如下
func Unmarshal(data []byte, v interface{}) error- 参数列表:包含两个参数
- 返回值:一个
error类型,表示解析过程中可能出现的错误,如果解析成功则返回nil。 - 这个函数的作用是将 JSON 格式的数据解析为 Go 语言中的数据结构,并将解析结果存储到目标数据结构中
获取代理目标URL
// getProxyURL 根据请求的网址和配置文件获取代理目标URL
func getProxyURL(req *http.Request) *url.URL {
host := req.Host
target, ok := ProxyConfig[host]
fmt.Println("A request comes: ", host, " ==> ", target)
if !ok {
return nil
}
proxyURL, err := url.Parse(target)
if err != nil {
log.Println("Error parsing proxy target URL:", err)
return nil
}
return proxyURL
}从http.Request中拿到请求的网址,并作为key从map中获取对应的value,使用url.Parse()将网址转换成*url.URL,返回
处理请求
func handleRequest(w http.ResponseWriter, r *http.Request) {
target := getProxyURL(r)
if target == nil {
http.Error(w, "Service not found", http.StatusNotFound)
return
}
proxy := httputil.NewSingleHostReverseProxy(target)
r.Host = target.Host // 重要,不添加会造成403forbidden
proxy.ServeHTTP(w, r)
}由之前的部分拿到了代理目标的*url.URL后,使用httputil.NewSingleHostReverseProxy() 创建一个反向代理,再使用ServeHTTP()将传入的第二个参数 HTTP 请求转发到目标服务器。
注意需要将target的host一并传过去,否则会造成403forbidden
main
func main() {
// 加载配置文件
err := loadConfig("config.json")
if err != nil {
log.Fatal("Failed to load configuration:", err)
}
// 打印映射,配置文件中的网址一定要添加好映射, /etc/hosts
for k, v := range ProxyConfig {
fmt.Printf("[%s] => %s\n", k, v)
}
// 设置监听的端口
http.HandleFunc("/", handleRequest)
log.Println("Starting proxy server on :80")
if err := http.ListenAndServe(":80", nil); err != nil {
log.Fatal("ListenAndServe: ", err)
}
}main()中要注意对错误的检查,并实现对端口的监听