CefSharp 3 在运行时设置代理

6
我下载了CEF(chromium嵌入式框架)二进制分发版,其中包括(cefclient和cefsimple)C ++示例,并意识到cefclient可以在运行时更改代理设置。而要实现这一点的关键是获取RequestContext并调用SetPreference函数。在CefClient上所有工作都很好。但在CefSharp上,调用SetPreference总是返回false,同时HasPreference对于偏好名称“proxy”也返回false。

1
跳转到 Gitter,阅读昨天的对话,你会找到所有需要的细节。很可能你在错误的线程上发起了调用,只有一个线程是有效的。https://gitter.im/cefsharp/CefSharp - amaitland
非常感谢,我一直在想如何在适当的线程上运行代码,但我被C++和C#包装器之间的代码差异分散了注意力。 - Aladdin
5个回答

8
感谢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=""
    });

1
我得到了“试图修改一个不可修改的引用”的错误信息。 - jLynx
@amaitland,您能否描述一下上面的内容在哪里以及如何使用?我想在Cef.Initialized之后在运行时更改代理,请告诉我。谢谢。 - confusedMind
我尝试了上述方法,但没有任何反应,它仍然使用我的默认IP地址。有什么建议吗? - confusedMind

4
如果有人需要其他解决方案,我找到了这个解决方案。
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;

请改进您源代码的描述。否则,此帖似乎没有为问题提供高质量答案。请编辑您的答案,或将其作为评论发布到问题中。 - sɐunıɔןɐqɐp
@amaitland,现在表达式 rc.SetPreference("proxy", v, out string error) 抛出了 System.NullReferenceException 异常,我检查了 rc.Equals(br.GetBrowser().GetHost().RequestContext) 并得到了 false。我期望 rc 只是当前 RequestContext 的引用。这是正常行为吗? - D. Nikitin
没有堆栈跟踪,我无法确切地说。 - amaitland
现在就回到你之前的状态。 - amaitland
@amaitland,感谢您的反馈,我已经修改了代码,现在它可以正常工作了。 - D. Nikitin
显示剩余2条评论

1
如果您想要动态代理解析器(代理处理程序),允许您为不同的主机使用不同的代理 - 您需要执行以下操作:

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://dev59.com/BpXfa4cB1Zd3GeqPbzkT#36106994调用SetPreference函数。

结果是所有对*example.com的请求都将通过proxy1流动,其他请求则通过proxy2。

为了做到这一点,我花了一整天的时间,但在源代码(https://cs.chromium.org/)的帮助下找到了解决方案。希望它能帮助到别人。

主要问题:

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

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

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


示例看起来不完整,你需要构建包的URL,而不是实际调用SetPreference,最好展示一个完整的示例。 - amaitland
忘了它,谢谢。添加第三步。 - Сергей Рыбаков
嗨@СергейРыбаков,你在哪里找到“pac_script”模式的?有没有一个地方可以看到可能的模式列表? - Juan
@Juan 对不起,我不知道在哪里找到所有的值。也许在源代码中? - Сергей Рыбаков

0

使用新版本的CefSharp,设置代理非常简单:

browser = new ChromiumWebBrowser();
panel1.Controls.Add(browser);
browser.Dock = DockStyle.Fill;
await browser.LoadUrlAsync("about:blank");
await Cef.UIThreadTaskFactory.StartNew(() =>
{
    browser.GetBrowser().GetHost().RequestContext.SetProxy("127.0.0.1", 1088, out string _);
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接