解决一下 WebView2 不能用 socket5代理的问题。

本文档详细介绍了如何在Webview2中使用自定义的Socket5代理进行数据转发,由于官方未提供相应API,作者通过编写代理转发代码实现了认证功能。主要涉及TCP监听、客户端和代理端的连接、数据读写以及代理认证过程。

webview2现在好像还能在启用s5代理的情况下,可以输入账号密码。应该是还没开发这个API。所以曲线解决了一下,记录一下吧。

解决就是自己写代理转发认证一下。直接上代码 

    /// <summary>    /// Socket代理5转发    /// </summary>    public class Socket5Forward    {        #region 类型 Type        #region 私有类型 Private        /// <summary>        /// 进度命令        /// </summary>        private enum Command        {            /// <summary>            /// 默认            /// </summary>            Default,            /// <summary>            /// 连接            /// </summary>            Connection,            /// <summary>            /// 验证            /// </summary>            Validate,            /// <summary>            /// 读写            /// </summary>            ReadWrite        }        /// <summary>        /// 异步状态对象        /// </summary>        private class StateObject        {            /// <summary>            /// 标识            /// </summary>            public long IntID { get; set; }            /// <summary>            /// 客户端-无认证            /// </summary>            public Socket ClientSocket { get; set; }            /// <summary>            /// 客户端-进度            /// </summary>            public Command ClientCommand { get; set; } = Command.Default;            /// <summary>            /// 客户端-数据包            /// </summary>            public List<ArraySegment<byte>> ClientRead { get; set; }            /// <summary>            /// 代理端-需认证            /// </summary>            public Socket ProxySocket { get; set; }            /// <summary>            /// 代理端-进度            /// </summary>            public Command ProxyCommand { get; set; } = Command.Default;            /// <summary>            /// 代理段-数据包            /// </summary>            public List<ArraySegment<byte>> ProxyRead { get; set; }        }        /// <summary>        /// 代理数据        /// </summary>        public class Proxy        {            /// <summary>            /// 代理IP            /// </summary>            public string IP { set; get; }            /// <summary>            /// 代理端口            /// </summary>            public int Port { set; get; }            /// <summary>            /// 代理用户            /// </summary>            public string User { set; get; }            /// <summary>            /// 代理密码            /// </summary>            public string Pass { set; get; }        }        #endregion 私有类型        #region 公开类型 Public        #endregion 公开类型        #endregion 类型        #region 属性 Propertie        #region 私有属性 Private        /// <summary>        /// 代理信息        /// </summary>        private Proxy ObjProxy { get; set; }        /// <summary>        /// 自增标识        /// </summary>        private long IntID { get; set; } = 0;        /// <summary>        /// 服务对象        /// </summary>        private TcpListener ObjServer { get; set; }        #endregion 私有属性        #endregion 属性        #region 构造 Constructor        /// <summary>        /// 构造对象        /// </summary>        /// <param name="sIp">代理IP</param>        /// <param name="nPort">代理端口</param>        /// <param name="sUser">代理用户</param>        /// <param name="sPass">代理密码</param>        public Socket5Forward(string sIp, int nPort, string sUser, string sPass)        {            ObjProxy = new Proxy            {                IP = sIp,                Port = nPort,                User = sUser,                Pass = sPass            };            AddLog(System.Text.Json.JsonSerializer.Serialize(ObjProxy));        }        public Socket5Forward(Proxy oProxy)        {            ObjProxy = oProxy;        }        #endregion  构造        #region 方法 Method        #region 私有方法 Private        /// <summary>        /// 日志        /// </summary>        /// <param name="sMsg"></param>        private static void AddLog(string sMsg)        {            System.Diagnostics.Trace.WriteLine(sMsg);            //Console.WriteLine(sMsg);        }        #region 客户端        /// <summary>        /// 客户端-接受连接        /// </summary>        /// <param name="iAR"></param>        private void ClientAccept(IAsyncResult iAR)        {            AddLog("客户端-连接");            var listener = iAR.AsyncState as TcpListener;            try            {                var oClientSocket = listener.EndAcceptSocket(iAR);                var oProxyScoket = new TcpClient();                var oState = new StateObject                {                    IntID = ++IntID,                    ClientSocket = oClientSocket,                    ClientCommand = Command.Connection,                    ClientRead = new List<ArraySegment<byte>>() { new ArraySegment<byte>(new byte[oClientSocket.ReceiveBufferSize]) },                    ProxySocket = oProxyScoket.Client,                    ProxyRead = new List<ArraySegment<byte>>() { new ArraySegment<byte>(new byte[oClientSocket.ReceiveBufferSize]) }                };                _ = oProxyScoket.BeginConnect(ObjProxy.IP, ObjProxy.Port, ProxyConnect, oState);                _ = listener.BeginAcceptSocket(ClientAccept, listener);            }            catch { }        }        /// <summary>        /// 客户端-读取->转发        /// </summary>        /// <param name="iAR"></param>        private void ClientRead(IAsyncResult iAR)        {            var oState = iAR.AsyncState as StateObject;            try            {                var nRead = oState.ClientSocket.EndReceive(iAR);                if (nRead > 0)                {                    if (oState.ClientCommand == Command.Connection)                    {                        AddLog($"[{oState.IntID}]客户端-请求命令");                        var nFristMethod = oState.ClientRead[0].Array[2];                        _ = oState.ClientSocket.Send(new byte[] { 0x05, nFristMethod });                        oState.ClientCommand = Command.ReadWrite;                    }                    else if (oState.ClientCommand == Command.ReadWrite)                    {                        //var sText = Encoding.UTF8.GetString(oState.ClientRead[0].Array, 0, nRead);                        //AddLog(sText);                        var nSend = oState.ProxySocket.Send(oState.ClientRead[0].Array, nRead, SocketFlags.None);                        AddLog($"[{oState.IntID}]客户端-转发数据包长度:R[{nRead}],S[{nSend}]");                    }                    _ = oState.ClientSocket.BeginReceive(oState.ClientRead, SocketFlags.None, ClientRead, oState);                }                else                {                    AddLog($"[{oState.IntID}]客户端-关闭:长度不足");                    oState.ClientSocket.Close();                    oState.ProxySocket.Close();                }            }            catch (Exception)            {                AddLog($"[{oState.IntID}]客户端-关闭:异常关闭");                oState.ClientSocket.Close();                oState.ProxySocket.Close();            }        }        #endregion        #region 代理端        /// <summary>        /// 代理端-连接完成        /// </summary>        /// <param name="iAR"></param>        private void ProxyConnect(IAsyncResult iAR)        {            try            {                AddLog("代理端已连接");                var oState = iAR.AsyncState as StateObject;                oState.ProxySocket.EndConnect(iAR);                oState.ProxyCommand = string.IsNullOrEmpty(ObjProxy.User) || string.IsNullOrEmpty(ObjProxy.Pass) ? Command.Validate : Command.Connection;                _ = oState.ProxySocket.Send(new byte[] { 0x05, 0x02, 0x00, 0x02 });                _ = oState.ProxySocket.BeginReceive(oState.ProxyRead, SocketFlags.None, ProxyRead, oState);            }            catch { }        }        /// <summary>        /// 代理端-读取->转发        /// </summary>        /// <param name="iAR"></param>        private void ProxyRead(IAsyncResult iAR)        {            var oState = iAR.AsyncState as StateObject;            try            {                var nRead = oState.ProxySocket.EndReceive(iAR);                if (nRead > 0)                {                    //AddLog($"[{oState.IntID}]ProxyRead====nRead > 0 nRead=" + nRead);                    if (oState.ProxyCommand == Command.Connection)                    {                        var arrBuf = oState.ProxyRead[0].Array;                        AddLog($"[{oState.IntID}]代理端-返回连接方法:{arrBuf[0]:x},{arrBuf[1]:x}");                        var oStream = new MemoryStream();                        oStream.WriteByte(0x1);                        oStream.WriteByte((byte)ObjProxy.User.Length);                        oStream.Write(Encoding.ASCII.GetBytes(ObjProxy.User));                        oStream.WriteByte((byte)ObjProxy.Pass.Length);                        oStream.Write(Encoding.ASCII.GetBytes(ObjProxy.Pass));                        _ = oState.ProxySocket.Send(oStream.ToArray());                        oStream.Close();                        oState.ProxyCommand = Command.Validate;                    }                    else if (oState.ProxyCommand == Command.Validate)                    {                        var arrBuf = oState.ProxyRead[0].Array;                        AddLog($"[{oState.IntID}]代理端-返回验证结果:{arrBuf[0]:x},{arrBuf[1]:x}");                        if (arrBuf[1] == 0x0)                        {                            AddLog($"[{oState.IntID}]客户端-接受数据");                            _ = oState.ClientSocket.BeginReceive(oState.ClientRead, SocketFlags.None, ClientRead, oState);                            oState.ProxyCommand = Command.ReadWrite;                        }                        else                        {                            AddLog($"[{oState.IntID}]代理端-认证错误");                            oState.ProxySocket.Close();                            oState.ClientSocket.Close();                        }                    }                    else if (oState.Pro 江西党性培训 www.ctbuganxun.com xyCommand == Command.ReadWrite)                    {                        //var sText = Encoding.UTF8.GetString(oState.ProxyRead[0].Array);                        var nSend = _ = oState.ClientSocket.Send(oState.ProxyRead[0].Array, nRead, SocketFlags.None);                        AddLog($"[{oState.IntID}]代理端-转发数据包长度:R[{nRead}],S[{nSend}]");                    }                    _ = oState.ProxySocket.BeginReceive(oState.ProxyRead, SocketFlags.None, ProxyRead, oState);                }                else                {                    AddLog($"[{oState.IntID}]代理端-关闭:长度不足");                    oState.ProxySocket.Close();                    oState.ClientSocket.Close();                }            }            catch (Exception)            {                AddLog($"[{oState.IntID}]代理端-关闭:异常");                oState.ProxySocket.Close();                oState.ClientSocket.Close();            }        }        #endregion        #endregion 私有方法        #region 公开方法 Public        /// <summary>        /// 开始服务        /// </summary>        /// <param name="nProt"></param>        public void Start(int nProt)        {            AddLog("开始");            try            {                ObjServer = new TcpListener(IPAddress.Any, nProt);                ObjServer.Start();                _ = ObjServer.BeginAcceptSocket(ClientAccept, ObjServer);            }            catch (Exception)            {                ObjServer = null;            }        }        public void Stop()        {            ObjServer?.Stop();        }        #endregion 公开方法        #endregion 方法    }

 

<think>嗯,用户之前问过关于ECharts的使用,现在又问前端跨域问题解决方案和代码。看来他们可能在开发前端项目,遇到了跨域的问题,需要具体的解决办法。 首先,用户可能是在本地开发时遇到了跨域,比如用Vue或React启动了一个本地服务器,然后请求后端API时出现跨域错误。这时候他们需要知道如何配置代理或者后端设置CORS。 然后,用户可能对跨域的基本概念不太清楚,需要先解释什么是跨域,同源策略的限制。不过用户直接要解决方案和代码,可能已经知道基础,但需要具体的方法。 常见的解决方案包括:后端设置CORS,前端配置代理,JSONP,Nginx反向代理,Webpack配置代理,postMessage,修改浏览器设置等。其中,CORS和代理是比较常用的,尤其是开发环境下,前端代理很常见。 需要详细说明每种方法的适用场景和具体实现步骤,比如CORS需要后端设置响应头,前端代理则是在开发服务器中配置,避免直接请求后端地址导致跨域。 还要注意安全性问题,比如CORS中不要滥用Access-Control-Allow-Origin为*,生产环境应该指定具体域名。Nginx配置反向代理时也要注意路径匹配和头信息传递。 另外,用户可能需要代码示例,比如如何在Express中设置CORS,Vue的vue.config.js怎么配代理,或者Nginx的配置片段。JSONP的例子虽然现在用的少,但可能某些旧项目还在用,也需要提及。 可能需要区分开发环境和生产环境的解决方案,开发时用代理,生产用Nginx或者后端处理。同时,提醒用户JSONP只支持GET请求,其他方法有局限性。 还要考虑用户的技术栈,比如他们之前用Vue3和ECharts,可能更熟悉Vue的代理配置,所以提供vue.config.js的例子会更实用。 总结下来,回答的结构应该是先解释跨域原因,再列出各种解决方案,每种方案给出适用场景、实现步骤和代码示例。最后给出最佳实践建议,帮助用户根据具体情况选择合适的方法。</think>以下是前端跨域问题的完整解决方案及代码实现指南,结合不同开发场景提供多种解决方式: --- ### 一、跨域本质解析 **同源策略限制**:当协议、域名、端口任一不同时触发跨域拦截 **典型错误**:`Access-Control-Allow-Origin`缺失导致的`No 'Access-Control-Allow-Origin'`错误 --- ### 二、解决方案分类 #### 1. 后端协作方案 **(1) CORS跨域资源共享** ```javascript // Node.js Express示例 app.use((req, res, next) => { res.header("Access-Control-Allow-Origin", "http://localhost:8080") // 精确白名单 res.header("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,OPTIONS") res.header("Access-Control-Allow-Headers", "Content-Type,Authorization") res.header("Access-Control-Allow-Credentials", "true") // 允许携带cookie req.method === 'OPTIONS' ? res.sendStatus(200) : next() }) ``` **(2) Nginx反向代理** ```nginx # nginx.conf配置片段 server { listen 80; server_name api.yourdomain.com; location / { proxy_pass http://localhost:3000; # 后端真实地址 add_header Access-Control-Allow-Origin $http_origin; add_header Access-Control-Allow-Methods *; add_header Access-Control-Allow-Headers *; if ($request_method = 'OPTIONS') { return 204; } } } ``` --- #### 2. 纯前端方案 **(1) 开发环境代理(Webpack/Vite)** ```javascript // vue.config.js module.exports = { devServer: { proxy: { '/api': { target: 'http://backend-service:3000', changeOrigin: true, pathRewrite: { '^/api': '' } } } } } ``` **(2) JSONP(仅限GET请求)** ```javascript function jsonp(url, callback) { const script = document.createElement('script') script.src = `${url}?callback=${callback}` document.body.appendChild(script) } // 全局定义回调函数 window.handleResponse = (data) => { console.log('Received:', data) } // 调用示例 jsonp('http://api.example.com/data', 'handleResponse') ``` **(3) postMessage跨窗口通信** ```javascript // 子窗口发送消息 window.parent.postMessage({ type: 'data', content: 'payload' }, 'http://parent-domain.com') // 主窗口监听 window.addEventListener('message', (event) => { if (event.origin !== 'http://child-domain.com') return console.log('Received:', event.data) }) ``` --- ### 三、特殊场景解决方案 #### 1. WebSocket跨域 ```javascript const ws = new WebSocket('ws://socket-server.com') // 协议升级自动跨域 ws.onopen = () => { ws.send('Connection established') } ``` #### 2. 跨域图片资源 ```html <img crossorigin="anonymous" src="http://external.com/image.jpg"> <!-- 需配合服务端设置Access-Control-Allow-Origin --> ``` #### 3. 本地文件协议跨域 ```bash # Chrome启动参数(开发测试用) chrome.exe --disable-web-security --user-data-dir="C:/temp" ``` --- ### 四、安全增强措施 1. **CORS白名单控制** ```javascript const allowOrigins = ['https://your-domain.com', 'http://localhost:8080'] app.use((req, res, next) => { const origin = req.headers.origin if (allowOrigins.includes(origin)) { res.setHeader('Access-Control-Allow-Origin', origin) } // ...其他配置 }) ``` 2. **CSRF Token验证** ```javascript // 前端在每个请求头携带token axios.interceptors.request.use(config => { config.headers['X-CSRF-Token'] = getCookie('csrfToken') return config }) ``` --- ### 五、最佳实践建议 1. **开发环境**:优先使用Webpack/Vite代理 2. **生产环境**: - 部署同域服务 - 必须跨域时使用Nginx反向代理+CORS 3. **敏感接口**: - 添加`Access-Control-Allow-Credentials: true` - 配合SameSite Cookie策略 4. **移动端Hybrid开发**: - 使用WebView自定义协议拦截 - 或通过Native Bridge中转请求 --- ### 六、调试工具验证 ```javascript // 使用fetch测试CORS配置 fetch('http://api.example.com/data', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ test: 1 }) }) .then(response => response.json()) .then(data => console.log(data)) .catch(error => console.error('CORS Error:', error)) ``` --- **方案选择决策树**: 1. 是否控制后端 → 是:CORS/Nginx 2. 仅前端控制 → 开发用代理,生产用JSONP/postMessage 3. 需要双向通信 → WebSocket 4. 旧系统兼容 → JSONP 通过合理组合这些方案,可以解决99%的前端跨域问题,建议优先采用标准化的CORS方案+反向代理模式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值