【问题标题】:CefSharp 3 set proxy at RuntimeCefSharp 3 在运行时设置代理
【发布时间】:2016-07-05 20:49:54
【问题描述】:

我下载了 (cefclient & cefsimple) c++ 示例附带的 CEF(chromuim 嵌入式框架)二进制分发,并意识到 cefclient 可以在运行时更改代理设置。

关键是获取RequestContext并调用函数SetPreference。

在 CefClient 上一切正常。

但在 CefSharp 上调用 SetPreference 总是返回 false,而且 HasPreference 也为首选项名称“proxy”返回 false。

【问题讨论】:

  • 跳到Gitter,阅读昨天的对话,你需要的所有细节。很可能您调用了不正确的线程,只有一个线程可以工作。 gitter.im/cefsharp/CefSharp
  • 非常感谢,a 想知道如何在正确的线程上运行代码,但我因 c++ 和 c# 包装器之间的代码差异而分心。

标签: c# c++ proxy chromium-embedded cefsharp


【解决方案1】:

感谢amaitland 主动强制更改请求上下文首选项的正确方法是在 CEF UIThread 上运行代码,如下所示:

    Cef.UIThreadTaskFactory.StartNew(delegate {
        var rc = this.browser.GetBrowser().GetHost().RequestContext;
        var v = new Dictionary<string, object>();
        v["mode"] = "fixed_servers";
        v["server"] = "scheme://host:port";
        string error;
        bool success = rc.SetPreference("proxy", v, out error);
        //success=true,error=""
    });

【讨论】:

  • 我收到“尝试修改用户不可修改的引用”
  • @amaitland 你能描述一下上面的位置和方式吗?我想在 Cef.Initialized 之后在运行时更改代理,所以请告诉我。谢谢
  • 我尝试了上述方法,但没有任何反应,它仍在使用我的默认 ip,有什么建议吗?
【解决方案2】:

如果有人需要任何其他的灵魂,我找到了这个解决方案。

Cef.UIThreadTaskFactory.StartNew(delegate
        {
            string ip = "ip or adress";
            string port = "port";
            var rc = this.browser.GetBrowser().GetHost().RequestContext;
            var dict = new Dictionary<string, object>();
            dict.Add("mode", "fixed_servers");
            dict.Add("server", "" + ip + ":" + port + "");
            string error;
            bool success = rc.SetPreference("proxy", dict, out error);

        });

【讨论】:

    【解决方案3】:

    我下载了 CefSharp.WinForms 65.0.0 并制作了课程,这有助于开始使用代理:

    public class ChromeTest
    {
        public static ChromiumWebBrowser Create(WebProxy proxy = null, Action<ChromiumWebBrowser> onInited = null)
        {
           var result = default(ChromiumWebBrowser);
            var settings = new CefSettings();
            result = new ChromiumWebBrowser("about:blank");
            if (proxy != null)
                result.RequestHandler = new _requestHandler(proxy?.Credentials as NetworkCredential);
    
            result.IsBrowserInitializedChanged += (s, e) =>
            {
                if (!e.IsBrowserInitialized)
                    return;
    
                var br = (ChromiumWebBrowser)s;
                if (proxy != null)
                {
                    var v = new Dictionary<string, object>
                    {
                        ["mode"] = "fixed_servers",
                        ["server"] = $"{proxy.Address.Scheme}://{proxy.Address.Host}:{proxy.Address.Port}"
                    };
                    if (!br.GetBrowser().GetHost().RequestContext.SetPreference("proxy", v, out string error))
                        MessageBox.Show(error);
                }
    
                onInited?.Invoke(br);
            };
    
            return result;
        }
    
        private class _requestHandler : DefaultRequestHandler
        {
            private NetworkCredential _credential;
    
            public _requestHandler(NetworkCredential credential = null) : base()
            {
                _credential = credential;
            }
    
            public override bool GetAuthCredentials(IWebBrowser browserControl, IBrowser browser, IFrame frame, bool isProxy, string host, int port, string realm, string scheme, IAuthCallback callback)
            {
                if (isProxy == true)
                {
                    if (_credential == null)
                        throw new NullReferenceException("credential is null");
    
                    callback.Continue(_credential.UserName, _credential.Password);
                    return true;
                }
    
                return false;
            }
        }
    }
    

    使用:

            var p = new WebProxy("Scheme://Host:Port", true, new[] { "" }, new NetworkCredential("login", "pass"));
            var p1 = new WebProxy("Scheme://Host:Port", true, new[] { "" }, new NetworkCredential("login", "pass"));
            var p2 = new WebProxy("Scheme://Host:Port", true, new[] { "" }, new NetworkCredential("login", "pass"));
    
            wb1 = ChromeTest.Create(p1, b => b.Load("http://speed-tester.info/check_ip.php"));
            groupBox1.Controls.Add(wb1);
            wb1.Dock = DockStyle.Fill;
    
            wb2 = ChromeTest.Create(p2, b => b.Load("http://speed-tester.info/check_ip.php"));
            groupBox2.Controls.Add(wb2);
            wb2.Dock = DockStyle.Fill;
    
            wb3 = ChromeTest.Create(p, b => b.Load("http://speed-tester.info/check_ip.php"));
            groupBox3.Controls.Add(wb3);
            wb3.Dock = DockStyle.Fill;
    

    【讨论】:

    • 锁定是为了什么?您所做的任何事情都不需要锁定。什么是字符串访问者? IsBrowserInitializedChanged 应该已经在 cef ui 线程上调用了,不需要创建任务。保留对您创建的 RequestContext 的引用并简化您的代码 您还应该包括您正在使用的 CefSharp 版本。
    • 请完善您的源代码描述。否则,这篇文章似乎没有为问题提供quality answer。请编辑您的答案,或将其作为对问题的评论发布。
    • 感谢@amaitland,抱歉,我没有完全清理工作解决方案中的代码并留下了一些碎片。我已经根据你的 cmets 编辑了代码。
    • @amaitland,现在表达式 rc.SetPreference("proxy", v, out string error) 抛出 System.NullReferenceException,我检查了 rc.Equals(br.GetBrowser().GetHost().RequestContext) 并得到 false。我预计 rc 只是对当前 RequestContext 的引用。这是正常行为吗?
    • 如果没有堆栈跟踪,我真的不能说。
    【解决方案4】:

    如果您想要动态代理解析器(proxy hanlder),它允许您为不同的主机使用不同的代理 - 您应该:

    1) 准备javascript

    var proxy1Str = "PROXY 1.2.3.4:5678";
    var proxy2Str = "PROXY 2.3.4.5:6789";
    
    var ProxyPacScript = 
        $"var proxy1 = \"{(proxy1Str.IsNullOrEmpty() ? "DIRECT" : proxy1Str)}\";" +
        $"var proxy2 = \"{(proxy2Str.IsNullOrEmpty() ? "DIRECT" : proxy2Str)}\";" +
    
        @"function FindProxyForURL(url, host) {
            if (shExpMatch(host, ""*example.com"")) {
                return proxy1;
            }
            return proxy2;
        }";
    
    var bytes = Encoding.UTF8.GetBytes(ProxyPacScript);
    var base64 = Convert.ToBase64String(bytes);
    

    2) 正确设置

    var v = new Dictionary<string, object>();
    v["mode"] = "pac_script";
    v["pac_url"] = "data:application/x-ns-proxy-autoconfig;base64," + base64;
    

    3) 在接受的答案https://stackoverflow.com/a/36106994/9252162 中调用 SetPreference

    因此,对 *example.com 的所有请求都将通过 proxy1,所有其他请求都通过 proxy2。

    为此,我花了一整天的时间,但在源 (https://cs.chromium.org/) 的帮助下,我找到了解决方案。希望它可以帮助某人。

    主要问题:

    1) 在新版本(我记得是 72 或 74)中,无法使用“file://...”作为 pac_url。

    2) 我们不能在 cef 中使用 https://developer.chrome.com/extensions/proxy.. 或者我找不到怎么做。

    附言如何使用其他类型的代理(https、socks) - https://chromium.googlesource.com/chromium/src/+/master/net/docs/proxy.md#evaluating-proxy-lists-proxy-fallback

    【讨论】:

    • 示例看起来不完整,你构建包url,实际上并没有调用SetPreference,最好显示一个完整的示例。
    • 忘记了。谢谢。添加第 3 步。
    • 嗨@СергейРыбаков 你在哪里找到“pac_script”模式?有没有可以看到可能模式列表的地方?
    • @Juan 对不起,我不知道在哪里可以找到所有值。可能在来源中?
    猜你喜欢
    • 1970-01-01
    • 2018-01-02
    • 2017-09-14
    • 2012-08-23
    • 1970-01-01
    • 2021-11-24
    • 1970-01-01
    • 2017-05-19
    相关资源
    最近更新 更多