当前位置: 首页 > news >正文

CEF与代理

此文已由作者王荣涛授权网易云社区发布。
欢迎访问网易云社区,了解更多网易技术产品运营经验。

CEF(Chromium Embedded Framework)如今已经广泛被应用于客户端软件,网易内部就有网易云音乐、有道云笔记等重要产品在深度使用。有时候我们需要让CEF在加载页面的时候走代理,比如科学上网,本文就以C++版的CEF为例,对CEF如何实现代理浏览作下简单介绍。

Chromium的代理
众所周知,CEF和Google Chrome都基于开源的Chromium浏览器项目。

固定代理
在Chromium中,你可以在启动时加入

--proxy-server="myproxy:808"或--proxy-server="http://myproxy:808"

开关用以显式告诉它走myproxy这台主机上808端口的HTTP代理(如果装了SwitchyOmega之类的代理控制软件,这种方式将不一定会按预期工作)。除此之外,Chromium还支持SOCKS4

--proxy-server="socks4://myproxy:1080"

以及SOCKS5方式的代理:

--proxy-server="socks://myproxy:1080"--proxy-server="socks5://myproxy:1080"

以及按不同URL类型指定不同的代理方式:

--proxy-server="https=http://myproxy:808;http=socks://myproxy:1080"

除此之外,结合--proxy-server开关,还可以使用--proxy-bypass-list开关来讲某些指定站点或者IP排除在使用代理的名单之外,例如:

--proxy-server="myproxy:808" --proxy-bypass-list="127.0.0.1;*.netease.com"

PAC
PAC(Proxy auto-config)文件本质上是一个包含FindProxyForURL函数的JS脚本,浏览器根据这个函数的返回结果来决定某个URL执行何种代理方式,一个例子如下:

function FindProxyForURL(url, host) {    if (isInNet(host, "10.240.0.0", "255.255.0.0"))        return "DIRECT";    return "SOCKS myproxy:1080";
}

Chromium支持PAC文件,开关如下:

--proxy-pac-url=URL

其中URL是你存放PAC文件的地方。大家熟悉的GoAgent等翻墙利器就只带这个文件,有兴趣的不妨可以翻出来看看。

其他开关
强制不使用代理

--no-proxy-server

自动探测代理

--proxy-auto-detect

CEF全局代理
CEF当然也支持Chromium方式的代理,我们只要选择但不限于以下二者之一:

1、在CEF初始化的时候将以上开关作为参数传入CefInitialize、CefExecuteProcess等之中;

2、实现自己的CefApp派生类,然后重载OnBeforeCommandLineProcessing方法:

class MyCefApp final : public CefApp {public:    void OnBeforeCommandLineProcessing(        const CefString& process_type,
        CefRefPtr<CefCommandLine> command_line) {        if (process_type.empty()) {
            command_line->AppendSwitch("--proxy-server=\"myproxy:808\"");
        }
    }private:
    IMPLEMENT_REFCOUNTING(MyCefApp)
};

但是以上方式都是一次性的,也就是你只有一次机会对命令行进行修改,之后所有请求都遵循这种代理方式,这种方式我们暂且称为全局代理。

全局代理的方式有很多局限性,比如有时候我只想对某个页面的内容使用代理,这种就完全不适用了,因为第一我们需要重启CEF,第二一旦设置了代理将会影响所有页面。

CEF任意请求代理
幸运的是,最新版(准确说是2015年10月7日之后)的CEF加入另一种更加灵活的方式,即任意请求代理。

这种方式的原理是在进行每次请求的时候CEF给应用一次机会让应用可以修改请求相关的参数。要实现这一点,我们需要自己的CefRequestHandler,然后重载OnBeforeBrowse和GetAuthCredentials(不一定需要)两个方法,定义如下:

class MyRequestHandler final : public CefRequestHandler {public:

    virtual bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
                                CefRefPtr<CefFrame> frame,
                                CefRefPtr<CefRequest> request,                                bool is_redirect);    // 可选,根据是否需要认证
    virtual bool GetAuthCredentials(CefRefPtr<CefBrowser> browser,
                                    CefRefPtr<CefFrame> frame,                                    bool isProxy,                                    const CefString& host,                                    int port,                                    const CefString& realm,                                    const CefString& scheme,
                                    CefRefPtr<CefAuthCallback> callback);private:    
    IMPLEMENT_REFCOUNTING(MyRequestHandler);
};

具体实现示例:

    bool MyRequestHandler::OnBeforeBrowse(
        CefRefPtr<CefBrowser> browser,
        CefRefPtr<CefFrame> frame,
        CefRefPtr<CefRequest> request,
        bool is_redirect) {
        CefRefPtr<CefRequestContext> context =
            browser->GetHost()->GetRequestContext();
        CefString error;
        CefRefPtr<CefDictionaryValue> dict = CefDictionaryValue::Create();
        dict->SetString("mode", "fixed_servers");
        dict->SetString("server", "myproxy:808");
        CefRefPtr<CefValue> value = CefValue::Create();
        value->SetDictionary(dict);
        context->SetPreference("proxy", value, error);    return false;
    }
    其中mode可以取值以下任一:
    fixed_servers
    pac_script
    auto_detect
    system
    direct
    而当mode为fixed_servers时需要指定server参数,当mode为pac_script时需要指定pac_url参数。
    如果代理需要认证,那么需要同时实现:
    bool MyRequestHandler::GetAuthCredentials(
        CefRefPtr<CefBrowser> browser,
        CefRefPtr<CefFrame> frame,    bool isProxy,    const CefString& host,    int port,    const CefString& realm,    const CefString& scheme,
        CefRefPtr<CefAuthCallback> callback) {    if (isProxy) {
            callback->Continue("myuser", "mypass");        return true;
        }    return false;
    }

题外话
CefRequestHandler::OnBeforeBrowse中可以干的还有很多,比如控制拼写检查等,大家可以好好去发掘。

网易云免费体验馆,0成本体验20+款云产品!

更多网易技术、产品、运营经验分享请点击。

文章来源: 网易云社区

相关文章:

  • VS2010安装与启动
  • jQuery快速入门
  • 线下比特币现金交易的区块链创企CoinText.io完成60万美元种子轮融资
  • SCOI2008着色方案(记忆化搜索)
  • 高性能iOS应用开发(二):应用的生命周期
  • Blockathon(2018)上海竞赛项目成果今天揭晓
  • 版本
  • idea的安装和学生申请免费使用
  • Python自动化开发学习-爬虫2
  • hadoop最新发行稳定版:DKHadoop版本选择详解
  • 多路复用实现单服百万级别RPS吞吐
  • 1024,码出未来!
  • 实验5
  • Sql Server内置函数实现MD5加密
  • [Google Guava] 1.1-使用和避免null
  • Java新版本的开发已正式进入轨道,版本号18.3
  • Logstash 参考指南(目录)
  • Spring-boot 启动时碰到的错误
  • Sublime text 3 3103 注册码
  • Tornado学习笔记(1)
  • 分布式熔断降级平台aegis
  • 基于Dubbo+ZooKeeper的分布式服务的实现
  • 极限编程 (Extreme Programming) - 发布计划 (Release Planning)
  • 如何利用MongoDB打造TOP榜小程序
  • 视频flv转mp4最快的几种方法(就是不用格式工厂)
  • 微信开源mars源码分析1—上层samples分析
  • 微信小程序实战练习(仿五洲到家微信版)
  • 我的业余项目总结
  • 小而合理的前端理论:rscss和rsjs
  • - 转 Ext2.0 form使用实例
  • C# - 为值类型重定义相等性
  • NLPIR智能语义技术让大数据挖掘更简单
  • Redis4.x新特性 -- 萌萌的MEMORY DOCTOR
  • 仓管云——企业云erp功能有哪些?
  • ​软考-高级-系统架构设计师教程(清华第2版)【第15章 面向服务架构设计理论与实践(P527~554)-思维导图】​
  • # 20155222 2016-2017-2 《Java程序设计》第5周学习总结
  • #多叉树深度遍历_结合深度学习的视频编码方法--帧内预测
  • (13):Silverlight 2 数据与通信之WebRequest
  • (175)FPGA门控时钟技术
  • (ZT)一个美国文科博士的YardLife
  • (动手学习深度学习)第13章 计算机视觉---微调
  • (二)构建dubbo分布式平台-平台功能导图
  • (二十一)devops持续集成开发——使用jenkins的Docker Pipeline插件完成docker项目的pipeline流水线发布
  • (附源码)spring boot火车票售卖系统 毕业设计 211004
  • (九)信息融合方式简介
  • (状压dp)uva 10817 Headmaster's Headache
  • **python多态
  • .NET Core跨平台微服务学习资源
  • .net 按比例显示图片的缩略图
  • .NET框架设计—常被忽视的C#设计技巧
  • .NET面试题(二)
  • @NoArgsConstructor和@AllArgsConstructor,@Builder
  • @selector(..)警告提示
  • @TableLogic注解说明,以及对增删改查的影响
  • @Tag和@Operation标签失效问题。SpringDoc 2.2.0(OpenApi 3)和Spring Boot 3.1.1集成