注入代理授权并将请求传输到远程代理的端口转发器
大家好,今天本人给大家带来文章《注入代理授权并将请求传输到远程代理的端口转发器》,文中内容主要涉及到,如果你对Golang方面的知识点感兴趣,那就请各位朋友继续看下去吧~希望能真正帮到你们,谢谢!
我实际上正在使用 go 构建一个基于 selenium 的自动化工具,称为 igopher,并且我想实现本机代理支持。
但是,我遇到了身份验证方面的问题...
我无法将代理凭据发送到 chrome,如果没有它们,它会通过一个警报框要求进行身份验证,而我几乎无法通过 selenium 进行交互(我什至不确定在无头模式下是否可行)。
所以我想到了一个由我的程序本地托管的中间代理系统,它将添加代理授权标头并将请求传输到远程代理:
我发现这个 nodejs 程序非常有用,我想在 go 中重现它。
主要部分如下:
function createportforwarder(local_host, local_port, remote_host, remote_port, buf_proxy_basic_auth, is_remote_https, ignore_https_cert) { net.createserver({allowhalfopen: true}, function (socket) { var realcon = (is_remote_https ? tls : net).connect({ port: remote_port, host: remote_host, allowhalfopen: true, rejectunauthorized: !ignore_https_cert /*not used when is_remote_https false*/ }); realcon.on('data', function (buf) { socket.write(buf); realcon.__havegotdata = true; }).on('end', function () { socket.end(); if (!realcon.__havegotdata && !realcon.__haveshownerror) { console.error('[localproxy(:' + local_port + ')][connection to ' + remote_host + ':' + remote_port + '] error: ended by remote peer'); realcon.__haveshownerror = true; } }).on('close', function () { socket.end(); if (!realcon.__havegotdata && !realcon.__haveshownerror) { console.error('[localproxy(:' + local_port + ')][connection to ' + remote_host + ':' + remote_port + '] error: reset by remote peer'); realcon.__haveshownerror = true; } }).on('error', function (err) { console.error('[localproxy(:' + local_port + ')][connection to ' + remote_host + ':' + remote_port + '] ' + err); realcon.__haveshownerror = true; }); var parser = new httpparser(httpparser.request); parser[httpparser.konheaderscomplete] = function (versionmajor, versionminor, headers, method, url, statuscode, statusmessage, upgrade, shouldkeepalive) { parser.__is_headers_complete = true; parser.__upgrade = upgrade; parser.__method = method; }; var state = state_none; socket.on('data', function (buf) { if (!parser) { realcon.write(buf); return } var buf_ary = [], unsavedstart = 0, buf_len = buf.length; for (var i = 0; i < buf_len; i++) { //find first lf if (state === state_none) { if (buf[i] === lf) { state = state_found_lf; } continue; } //find second cr lf or lf if (buf[i] === lf) { parser.__is_headers_complete = false; parser.execute(buf.slice(unsavedstart, i + 1)); if (parser.__is_headers_complete) { buf_ary.push(buf.slice(unsavedstart, buf[i - 1] === cr ? i - 1 : i)); //insert auth header buf_ary.push(buf_proxy_basic_auth); buf_ary.push(state === state_found_lf_cr ? buf_cr_lf_cr_lf : buf_lf_lf); // stop intercepting packets if encountered tls and websocket handshake if (parser.__method === 5 /*connect*/ || parser.__upgrade) { parser.close(); parser = null; buf_ary.push(buf.slice(i + 1)); realcon.write(buffer.concat(buf_ary)); state = state_none; return; } unsavedstart = i + 1; state = state_none; } else { state = state_found_lf; } } else if (buf[i] === cr && state === state_found_lf) { state = state_found_lf_cr; } else { state = state_none; } } if (unsavedstart < buf_len) { buf = buf.slice(unsavedstart, buf_len); parser.execute(buf); buf_ary.push(buf); } realcon.write(buffer.concat(buf_ary)); }).on('end', cleanup).on('close', cleanup).on('error', function (err) { if (!socket.__cleanup) { console.error('[localproxy(:' + local_port + ')][incoming connection] ' + err); } }); function cleanup() { socket.__cleanup = true; if (parser) { parser.close(); parser = null; } realcon.end(); } }).on('error', function (err) { console.error('[localproxy(:' + local_port + ')] ' + err); process.exit(1); }).listen(local_port, local_host === '*' ? undefined : local_host, function () { console.log('[localproxy(:' + local_port + ')] ok: forward http://' + local_host + ':' + local_port + ' to http' + (is_remote_https ? 's' : '') + '://' + remote_host + ':' + remote_port); }); }
可以在 go 中重现吗?我找到了 tcp 转发器的要点,但我不知道是否可以用它编辑请求标头...
如果这是不可能的(这会让我感到惊讶),我仍然可以在我自己的程序中使用这个节点程序,但我真的更愿意避免使节点成为依赖项。
此外,将其本地包含在我的程序中将使与它的交互变得更容易,特别是能够停止或重新启动该服务器。
因此,如果有人有想法、建议或资源,会对我有很大帮助!我被这个问题困扰了很长时间......
提前致谢!
编辑:
我已经尝试使用 reverseproxy 但没有成功,修改后它无法将请求发送到远程代理,因为它是 connect 代理并且 url 的格式为 //ip:port例如://google.com:443。
这是我的代码:
func printresponse(r *http.response) error { logrus.infof("response: %+v\n", r) return nil } // launchforwardingproxy launch forward server used to inject proxy authentication header // into outgoing requests func launchforwardingproxy(localport uint16, remoteproxy proxyconfig) error { localserverhost = fmt.sprintf("localhost:%d", localport) remoteserverhost = fmt.sprintf( "http://%s:%d", remoteproxy.ip, remoteproxy.port, ) remoteserverauth = fmt.sprintf( "%s:%s", remoteproxy.username, remoteproxy.password, ) remote, err := url.parse(remoteserverhost) if err != nil { panic(err) } proxy := httputil.newsinglehostreverseproxy(remote) d := func(req *http.request) { logrus.infof("pre-edited request: %+v\n", req) req.host = remoteserverhost // inject proxy authentication headers to outgoing request into new header basicauth := "basic " + base64.stdencoding.encodetostring([]byte(remoteserverauth)) req.header.set("proxy-authorization", basicauth) logrus.infof("edited request: %+v\n", req) logrus.infof("scheme: %s, host: %s, port: %s\n", req.url.scheme, req.url.host, req.url.port()) } proxy.director = d proxy.modifyresponse = printresponse http.listenandserve(localserverhost, proxy) return nil }
curl https://google.com --proxy http://127.0.0.1:8880 输出:
INFO[0013] Pre-Edited request: &{Method:CONNECT URL://google.com:443 Proto:HTTP/1.1 ProtoMajor:1 ProtoMinor:1 Header:map[Proxy-Connection:[Keep-Alive] User-Agent:[curl/7.68.0]] Body:GetBody: ContentLength:0 TransferEncoding:[] Close:false Host:google.com:443 Form:map[] PostForm:map[] MultipartForm: Trailer:map[] RemoteAddr:127.0.0.1:54126 RequestURI:google.com:443 TLS: Cancel: Response: ctx:0xc000674280} function=func1 line=59 INFO[0013] Edited Request: &{Method:CONNECT URL://google.com:443 Proto:HTTP/1.1 ProtoMajor:1 ProtoMinor:1 Header:map[Proxy-Authorization:[Basic auth] Proxy-Connection:[Keep-Alive] User-Agent:[curl/7.68.0]] Body: GetBody: ContentLength:0 TransferEncoding:[] Close:false Host:http://51.178.xx.xx:3128 Form:map[] PostForm:map[] MultipartForm: Trailer:map[] RemoteAddr:127.0.0.1:54126 RequestURI:google.com:443 TLS: Cancel: Response: ctx:0xc000674280} function=func1 line=67 INFO[0013] Scheme: , Host: google.com:443, Port: 443 function=func1 line=68 2021/03/16 21:53:51 http: proxy error: unsupported protocol scheme ""
解决方案
看看这段代码,它演示了您之前提出的方案
package main import ( "encoding/base64" "fmt" "io/ioutil" "log" "net/http" "net/http/httputil" "net/url" "time" auth "github.com/abbot/go-http-auth" ) func Secret(user, realm string) string { if user == "john" { // password is "hello" return "$1$dlPL2MqE$oQmn16q49SqdmhenQuNgs1" } return "" } func serveWithAuth() { authenticator := auth.NewBasicAuthenticator("localhost", Secret) http.HandleFunc("/", authenticator.Wrap(func(w http.ResponseWriter, r *auth.AuthenticatedRequest) { fmt.Fprintf(w, "Hello, %s!
", r.Username) })) http.ListenAndServe(":8080", nil) } func serveNoAuth(backURL string) { rpURL, err := url.Parse(backURL) if err != nil { log.Fatal(err) } p := NewSingleHostReverseProxy(rpURL) srv := &http.Server{Handler: p, Addr: ":9090"} srv.ListenAndServe() } func NewSingleHostReverseProxy(target *url.URL) *httputil.ReverseProxy { rp := httputil.NewSingleHostReverseProxy(target) director := rp.Director rp.Director = func(req *http.Request) { director(req) if target.User != nil { b := base64.StdEncoding.EncodeToString([]byte(target.User.String())) req.Header.Set("Authorization", fmt.Sprintf("Basic %v", string(b))) } } return rp } func main() { go serveWithAuth() go serveNoAuth("http://john:hello@localhost:8080/") <-time.After(time.Second) resp, err := http.Get("http://localhost:9090/") if err != nil { log.Fatal(err) } b, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Printf("%s", b) }
好了,本文到此结束,带大家了解了《注入代理授权并将请求传输到远程代理的端口转发器》,希望本文对你有所帮助!关注golang学习网公众号,给大家分享更多Golang知识!

- 上一篇
- Win11怎么不显示聚焦图片? 通过注册表设置是否显示聚焦图片的方法

- 下一篇
- 人工智能与云:虚拟世界中的绝配!
-
- Golang · Go问答 | 1年前 |
- 在读取缓冲通道中的内容之前退出
- 139浏览 收藏
-
- Golang · Go问答 | 1年前 |
- 戈兰岛的全球 GOPRIVATE 设置
- 204浏览 收藏
-
- Golang · Go问答 | 1年前 |
- 如何将结构作为参数传递给 xml-rpc
- 325浏览 收藏
-
- Golang · Go问答 | 1年前 |
- 如何用golang获得小数点以下两位长度?
- 477浏览 收藏
-
- Golang · Go问答 | 1年前 |
- 如何通过 client-go 和 golang 检索 Kubernetes 指标
- 486浏览 收藏
-
- Golang · Go问答 | 1年前 |
- 将多个“参数”映射到单个可变参数的习惯用法
- 439浏览 收藏
-
- Golang · Go问答 | 1年前 |
- 将 HTTP 响应正文写入文件后出现 EOF 错误
- 357浏览 收藏
-
- Golang · Go问答 | 1年前 |
- 结构中映射的匿名列表的“复合文字中缺少类型”
- 352浏览 收藏
-
- Golang · Go问答 | 1年前 |
- NATS Jetstream 的性能
- 101浏览 收藏
-
- Golang · Go问答 | 1年前 |
- 如何将复杂的字符串输入转换为mapstring?
- 440浏览 收藏
-
- Golang · Go问答 | 1年前 |
- 相当于GoLang中Java将Object作为方法参数传递
- 212浏览 收藏
-
- Golang · Go问答 | 1年前 |
- 如何确保所有 goroutine 在没有 time.Sleep 的情况下终止?
- 143浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 542次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 508次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 497次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 484次学习
-
- 笔灵AI生成答辩PPT
- 探索笔灵AI生成答辩PPT的强大功能,快速制作高质量答辩PPT。精准内容提取、多样模板匹配、数据可视化、配套自述稿生成,让您的学术和职场展示更加专业与高效。
- 24次使用
-
- 知网AIGC检测服务系统
- 知网AIGC检测服务系统,专注于检测学术文本中的疑似AI生成内容。依托知网海量高质量文献资源,结合先进的“知识增强AIGC检测技术”,系统能够从语言模式和语义逻辑两方面精准识别AI生成内容,适用于学术研究、教育和企业领域,确保文本的真实性和原创性。
- 38次使用
-
- AIGC检测-Aibiye
- AIbiye官网推出的AIGC检测服务,专注于检测ChatGPT、Gemini、Claude等AIGC工具生成的文本,帮助用户确保论文的原创性和学术规范。支持txt和doc(x)格式,检测范围为论文正文,提供高准确性和便捷的用户体验。
- 38次使用
-
- 易笔AI论文
- 易笔AI论文平台提供自动写作、格式校对、查重检测等功能,支持多种学术领域的论文生成。价格优惠,界面友好,操作简便,适用于学术研究者、学生及论文辅导机构。
- 50次使用
-
- 笔启AI论文写作平台
- 笔启AI论文写作平台提供多类型论文生成服务,支持多语言写作,满足学术研究者、学生和职场人士的需求。平台采用AI 4.0版本,确保论文质量和原创性,并提供查重保障和隐私保护。
- 41次使用
-
- GoLand调式动态执行代码
- 2023-01-13 502浏览
-
- 用Nginx反向代理部署go写的网站。
- 2023-01-17 502浏览
-
- Golang取得代码运行时间的问题
- 2023-02-24 501浏览
-
- 请问 go 代码如何实现在代码改动后不需要Ctrl+c,然后重新 go run *.go 文件?
- 2023-01-08 501浏览
-
- 如何从同一个 io.Reader 读取多次
- 2023-04-11 501浏览