CEF框架:各种各样的Handle(四)——CefURLRequest,发起HTTP请求与处理

news2024/9/8 10:34:10

文章目录

  • CEF的HTTP请求类
    • CefResourceRequest
    • CefURLRequest
  • CefURLRequest的使用
    • cef_message_route
    • handled:urlrequet的处理类
      • OnQuery
  • CefURLRequestClient

CEF的HTTP请求类

在CEF框架中(Chromium Embedded Framework),CefURLRequestCefResourceRequest确实是两个不同的功能类,它们的主要区别在于使用场景和功能:

CefResourceRequest

  • 这个类通常用于加载资源类型的请求,比如在渲染网页时加载HTML文件、脚本、样式表、图片等。
  • CefResourceRequest主要用于内部处理浏览器的渲染操作,例如当浏览器需要获取并显示一个页面上的资源时。
  • 它通常不会直接暴露给通过CEF构建应用程序的开发者,除非开发者打算实现自定义的资源加载逻辑。
  • 简单的说,这个类用于控制在浏览器渲染时使用,发起和结束都不是程序来控制,只是说可以获得其中的过程数据进行处理,在上一篇CEF框架:各种各样的Handle(三)——拦截Http的请求与响应中已经有详细的说明。

CefURLRequest

  • CefURLRequest是一个更通用的请求类,它可以用于任何类型的HTTP请求,包括异步的和非阻塞的网络访问。
  • 开发者可以使用这个类来执行自定义的HTTP请求,如下载文件、提交表单数据、访问RESTful API等。
  • 它提供了一组回调接口(CefURLRequestClient),使开发者可以对请求过程中的各种事件作出响应,如开始请求、完成请求、错误发生、数据可用等。
  • 也就是说,当服务器需要自己来发起HTTP请求的时候,比如要发起GET,POST,DELETE等请求的时候,就可以使用CefURLRequest来发起。

CefURLRequest的使用

在CEF的框架示例代码中,cefclient就给出了如何使用CefURLRequest类的例子:

这个代码在resource/urlrequest.html文件中,这个文件中关键的代码就是这个按钮,也就是发起http请求的代码:

function execURLRequest() {
  document.getElementById('ta').value = 'Request pending...';

  // Results in a call to the OnQuery method in urlrequest_test.cpp
  window.cefQuery({
    request: 'URLRequestTest:' + document.getElementById("url").value,
    onSuccess: function(response) {
      document.getElementById('ta').value = response;
    },
    onFailure: function(error_code, error_message) {
      document.getElementById('ta').value = 'Failed with error ' + error_message + ' (' + error_code + ')';
    }
  });
}

可以看到,就是调用了CEF框架中封装的cefQuery函数,详情在最早的一篇CEF文章中就提到过:CEF消息传递实战(实测可用,新鲜出炉)。

cef_message_route

在CEF消息传递实战(实测可用,新鲜出炉)中也提到了,是需要定义一个Handler来处理前端JS调用的cefQuery请求的。在CEF的框架示例代码CEFSIMPLE中,可以新定义一个Handler来处理。

在CEFCLIENT中,定义了一个消息的路由中心,这个路由器在cef_message_route文件中:

  • 统一的消息处理类

    class CefMessageRouterBrowserSideImpl : public CefMessageRouterBrowserSide
    {
       ...
    
       bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
                                  CefRefPtr<CefFrame> frame,
                                  CefProcessId source_process,
                                    CefRefPtr<CefProcessMessage> message) OVERRIDE {
        CEF_REQUIRE_UI_THREAD();
    
        const std::string& message_name = message->GetName();
        if (message_name == query_message_name_) {
          CefRefPtr<CefListValue> args = message->GetArgumentList();
          DCHECK_EQ(args->GetSize(), 4U);
    
          const int context_id = args->GetInt(0);
          const int request_id = args->GetInt(1);
          const CefString& request = args->GetString(2);
          const bool persistent = args->GetBool(3);
    
          if (handler_set_.empty()) {
            // No handlers so cancel the query.
            CancelUnhandledQuery(browser, frame, context_id, request_id);
            return true;
          }
    
          const int browser_id = browser->GetIdentifier();
          const int64 query_id = query_id_generator_.GetNextId();
    
          CefRefPtr<CallbackImpl> callback(
              new CallbackImpl(this, browser_id, query_id, persistent));
    
          // Make a copy of the handler list in case the user adds or removes a
          // handler while we're iterating.
          HandlerSet handler_set = handler_set_;
    
          bool handled = false;
          HandlerSet::const_iterator it_handler = handler_set.begin();
          for (; it_handler != handler_set.end(); ++it_handler) {
            handled = (*it_handler)
                          ->OnQuery(browser, frame, query_id, request, persistent,
                                    callback.get());
            if (handled)
              break;
          }
    
          // If the query isn't handled nothing should be keeping a reference to
          // the callback.
          DCHECK(handled || callback->HasOneRef());
    
          if (handled) {
            // Persist the query information until the callback executes.
            // It's safe to do this here because the callback will execute
            // asynchronously.
            QueryInfo* info = new QueryInfo;
            info->browser = browser;
            info->frame = frame;
            info->context_id = context_id;
            info->request_id = request_id;
            info->persistent = persistent;
            info->callback = callback;
            info->handler = *(it_handler);
            browser_query_info_map_.Add(browser_id, query_id, info);
          } else {
            // Invalidate the callback.
            callback->Detach();
    
            // No one chose to handle the query so cancel it.
            CancelUnhandledQuery(browser, frame, context_id, request_id);
          }
    
          return true;
        } else if (message_name == cancel_message_name_) {
          CefRefPtr<CefListValue> args = message->GetArgumentList();
          DCHECK_EQ(args->GetSize(), 2U);
    
          const int browser_id = browser->GetIdentifier();
          const int context_id = args->GetInt(0);
          const int request_id = args->GetInt(1);
    
          CancelPendingRequest(browser_id, context_id, request_id);
          return true;
        }
    
        return false;
      }
    
       ...
    }
    

    这段代码中通过Handler调用具体的处理类,handled = (*it_handler) ->OnQuery(browser, frame, query_id, request, persistent, callback.get());

handled:urlrequet的处理类

urlrequet的处理类定义在urlrequest_test.cc类中:

// Handle messages in the browser process. Only accessed on the UI thread.
class Handler : public CefMessageRouterBrowserSide::Handler {
 public:
  Handler() { CEF_REQUIRE_UI_THREAD(); }

  ~Handler() { CancelPendingRequest(); }

  // Called due to cefQuery execution in urlrequest.html.
  bool OnQuery(CefRefPtr<CefBrowser> browser,
               CefRefPtr<CefFrame> frame,
               int64 query_id,
               const CefString& request,
               bool persistent,
               CefRefPtr<Callback> callback) OVERRIDE {
    CEF_REQUIRE_UI_THREAD();

    // Only handle messages from the test URL.
    const std::string& url = frame->GetURL();
    if (!test_runner::IsTestURL(url, kTestUrlPath))
      return false;

    const std::string& message_name = request;
    if (message_name.find(kTestMessageName) == 0) {
      const std::string& load_url =
          message_name.substr(sizeof(kTestMessageName));

      CancelPendingRequest();

      DCHECK(!callback_.get());
      DCHECK(!urlrequest_.get());

      callback_ = callback;

      // Create a CefRequest for the specified URL.
      CefRefPtr<CefRequest> cef_request = CefRequest::Create();
      cef_request->SetURL(load_url);
      cef_request->SetMethod("GET");

      // Callback to be executed on request completion.
      // It's safe to use base::Unretained() here because there is only one
      // RequestClient pending at any given time and we explicitly detach the
      // callback in the Handler destructor.
      const RequestClient::Callback& request_callback =
          base::Bind(&Handler::OnRequestComplete, base::Unretained(this));

      // Create and start a new CefURLRequest associated with the frame, so
      // that it shares authentication with ClientHandler::GetAuthCredentials.
      urlrequest_ = frame->CreateURLRequest(
          cef_request, new RequestClient(request_callback));

      return true;
    }

    return false;
  }

 private:
  // Cancel the currently pending URL request, if any.
  void CancelPendingRequest() {
    CEF_REQUIRE_UI_THREAD();

    if (urlrequest_.get()) {
      // Don't execute the callback when we explicitly cancel the request.
      static_cast<RequestClient*>(urlrequest_->GetClient().get())->Detach();

      urlrequest_->Cancel();
      urlrequest_ = nullptr;
    }

    if (callback_.get()) {
      // Must always execute |callback_| before deleting it.
      callback_->Failure(ERR_ABORTED, test_runner::GetErrorString(ERR_ABORTED));
      callback_ = nullptr;
    }
  }

  void OnRequestComplete(CefURLRequest::ErrorCode error_code,
                         const std::string& download_data) {
    CEF_REQUIRE_UI_THREAD();

    if (error_code == ERR_NONE)
      callback_->Success(download_data);
    else
      callback_->Failure(error_code, test_runner::GetErrorString(error_code));

    callback_ = nullptr;
    urlrequest_ = nullptr;
  }

  CefRefPtr<Callback> callback_;
  CefRefPtr<CefURLRequest> urlrequest_;

  DISALLOW_COPY_AND_ASSIGN(Handler);
};

OnQuery

这个函数就是响应html文件中的JS事件的响应函数。

  • const std::string& load_url = message_name.substr(sizeof(kTestMessageName)); 过滤掉filter的关键字,留下HTTP请求的url地址。

  • 创建http请求

    // Create a CefRequest for the specified URL.
    CefRefPtr<CefRequest> cef_request = CefRequest::Create();
    cef_request->SetURL(load_url);
    cef_request->SetMethod("GET");
    
  • 提交http请求

    urlrequest_ = frame->CreateURLRequest(
        cef_request, new RequestClient(request_callback));
    

    简单来说,就是把这个request请求提交到对应的服务端了。

  • 再创建一个callback(一个函数指针),这个callback不是cef框架到JS界面的callback,而是urlrequest类相关的,处理整个http请求各关键事件的callback。

    // Callback to be executed on request completion.
    // It's safe to use base::Unretained() here because there is only one
    // RequestClient pending at any given time and we explicitly detach the
    // callback in the Handler destructor.
    const RequestClient::Callback& request_callback =
        base::Bind(&Handler::OnRequestComplete, base::Unretained(this));
    
  • OnRequestComplete,也就是当requst请求得到响应后,CEF框架就会调用这个函数,在上面的代码中可以看到,就是调用了callback_方法(这个callback就是记录了JS的匿名方法了),把对应的download_data返回到前端显示。

CefURLRequestClient

前面提到的都是从JS到CEF框架,然后再到消息路由,最后到某种消息的处理HANDLE,而这个消息HANDLE中最后才调用到整个URLREQUEST的框架HANDLE:CefURLRequestClient,定义在cef_urlrequest.h中。

class CefURLRequestClient : public virtual CefBaseRefCounted {
 public:
  virtual void OnRequestComplete(CefRefPtr<CefURLRequest> request) = 0;

  virtual void OnUploadProgress(CefRefPtr<CefURLRequest> request,
                                int64 current,
                                int64 total) = 0;

  virtual void OnDownloadProgress(CefRefPtr<CefURLRequest> request,
                                  int64 current,
                                  int64 total) = 0;

  virtual void OnDownloadData(CefRefPtr<CefURLRequest> request,
                              const void* data,
                              size_t data_length) = 0;

  virtual bool GetAuthCredentials(bool isProxy,
                                  const CefString& host,
                                  int port,
                                  const CefString& realm,
                                  const CefString& scheme,
                                  CefRefPtr<CefAuthCallback> callback) = 0;
};

为了节省篇幅,我将这个类中的所有注释全部去掉了,这个类就是定义了在HTTP请求的整个过程中,几个关键事件的钩子函数,这个几个函数都是纯虚函数,所以需要完成URLREQUEST的使用的话,自定义一个类对这个几个函数都需要重定义。

在CEF的示例中,代码为:

class RequestClient : public CefURLRequestClient {
 public:
  // Callback to be executed on request completion.
  typedef base::Callback<void(CefURLRequest::ErrorCode /*error_code*/,
                              const std::string& /*download_data*/)>
      Callback;

  explicit RequestClient(const Callback& callback) : callback_(callback) {
    CEF_REQUIRE_UI_THREAD();
    DCHECK(!callback_.is_null());
  }

  void Detach() {
    CEF_REQUIRE_UI_THREAD();
    if (!callback_.is_null())
      callback_.Reset();
  }

  void OnRequestComplete(CefRefPtr<CefURLRequest> request) OVERRIDE {
    CEF_REQUIRE_UI_THREAD();
    if (!callback_.is_null()) {
      callback_.Run(request->GetRequestError(), download_data_);
      callback_.Reset();
    }
  }

  void OnUploadProgress(CefRefPtr<CefURLRequest> request,
                        int64 current,
                        int64 total) OVERRIDE {}

  void OnDownloadProgress(CefRefPtr<CefURLRequest> request,
                          int64 current,
                          int64 total) OVERRIDE {}

  void OnDownloadData(CefRefPtr<CefURLRequest> request,
                      const void* data,
                      size_t data_length) OVERRIDE {
    CEF_REQUIRE_UI_THREAD();
    download_data_ += std::string(static_cast<const char*>(data), data_length);
    std::cout << download_data_ << std::endl;
  }

  bool GetAuthCredentials(bool isProxy,
                          const CefString& host,
                          int port,
                          const CefString& realm,
                          const CefString& scheme,
                          CefRefPtr<CefAuthCallback> callback) OVERRIDE {
    return false;
  }

 private:
  Callback callback_;
  std::string download_data_;

  IMPLEMENT_REFCOUNTING(RequestClient);
  DISALLOW_COPY_AND_ASSIGN(RequestClient);
};

几个纯虚函数的具体作用,可以参考cef_urlrequest.h中的注释,而且从名字也很容易判断出来,也就是CEF框架对这种通过的URL请求提供了这些自定义能力。

在这个示例中,主要就是通过定义OnDownloadData方法,来将所有的下载到的内容放到download_data_字符串中(CEF每次下载的大小由trunk大小来控制)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1703067.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ChaosMeta V0.7.0 版本发布 进入CNCF混沌工程全景图

混沌工程 ChaosMeta 的全新版本 V0.7.0 现已正式发布&#xff01;该版本包含了许多新特性和增强功能&#xff0c;在编排界面提供了多集群管理&#xff0c;在代码层面支持多命令下发通道的选择。另外由蚂蚁集团发起的ChaosMeta于北京时间2024年1月10日正式进入CNCF混沌工程全景图…

攻击者常用的五个数据中转网站

近来&#xff0c;各种数据中转网站被攻击者广泛用于传播代码片段、配置文件和各种文本数据&#xff0c;尽管这为研究人员提供了观察的窗口&#xff0c;但敏感信息被上传到互联网上时&#xff0c;也会对受害者构成巨大威胁。 这些网站通常并不需要注册或者身份验证&#xff0c;…

AI大模型日报#0527:豆包大模型披露评测成绩、天工AI日活超100万、AI初创集体跳槽OpenAI

导读&#xff1a;AI大模型日报&#xff0c;爬虫LLM自动生成&#xff0c;一文览尽每日AI大模型要点资讯&#xff01;目前采用“文心一言”&#xff08;ERNIE 4.0&#xff09;、“零一万物”&#xff08;Yi-Large&#xff09;生成了今日要点以及每条资讯的摘要。欢迎阅读&#xf…

9.游戏中真正的无敌

上一个内容&#xff1a;8.什么是HOOK 在 7.封装读写游戏数据的功能2 中写是无限循环给生命值的内存地址赋值达到无敌的效果&#xff0c;这个方式有很大的弊端比如如果怪物的攻击力很高我们碰一下我们就得死这样的情况无限赋值也没用了&#xff0c;所以给内存写值的方式实现的无…

HTTP 与 HTTPS 对比

HTTP&#xff1a;HTTPS&#xff1a;超文本传输协议 超文本传输安全协议加入SSL/TLS协议&#xff0c;依靠证书来验证服务器的身份需要到CA申请证书&#xff0c;需要一定费用TCP 协议 80 端口 TCP 协议 443 端口更耗费服务器资源

深度学习环境安装教程-anaconda-python-pytorch

首先是anaconda的安装&#xff0c;可以从下面地址下载安装包 Index of /anaconda/archive/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror 尽量选择最新的日期的anaconda进行安装&#xff0c;我这里是windows电脑&#xff0c;因此选择了windos-x86_64.exe&#xf…

idea中git拉取失败

之前clone好好的&#xff0c;今天突然就拉取不下来了。很多时候是用户凭证的信息没更新的问题。由于window对同一个地址都存储了会话。如果是新的会话&#xff0c;必须要更新window下的凭证。 然后根据你的仓库找到你对应的账户&#xff0c;更新信息即可。

Windows10映射网络驱动器之后不显示映射盘

目录 背景解决步骤1、按 Windows R 打开运行2、打开注册表编辑器3、 System上新建-- DWORD(32bit)4、对新建的文件重命名5、将EnableLinkedConnections的数值改为16、退出注册表编辑器&#xff0c;重启系统。 知识扩展断开连接备份注册表 背景 目前有一台NAS服务器,和一台lin…

知了汇智赵老师:揭秘OpenHarmony鸿蒙设备开发新路径

在数字化浪潮风起云涌的今天&#xff0c;鸿蒙系统作为华为自主研发的分布式操作系统&#xff0c;正以其强大的生态构建能力和广泛的应用前景&#xff0c;引领着物联网领域的新潮流。在这个关键时刻&#xff0c;知了汇智作为产教融合平台型服务机构&#xff0c;勇担时代使命&…

网络通讯聊天工具的实现

学习网络与通信&#xff0c;实现聊天界面能够通过服务器进行私聊和群聊的功能。 1.服务器&#xff1a;ServeSocket 客户端先发送消息给服务器&#xff0c;服务器接受消息后再发送给客户端。 利用服务器随时监听。等待客户端的请求&#xff0c;一旦有请求便生产一个socket套接…

openEuler系统通过shell脚本安装openGauss 5.0.0企业版

上次提到的开机自启动的配置&#xff0c;获得了LD的称赞&#xff0c;然而LD的要求&#xff0c;都是“既得陇复望蜀”的&#xff0c;他又期望我们能实现openGauss安装的“自动化”&#xff0c;于是尝试了下用shell脚本部署&#xff0c;附件中的脚本实测有效&#xff0c;openEule…

aws lakeformation跨账号共享数据的两种方式和相关配置

lakeformation授权方式分为 基于tag的授权基于命名资源的授权 先决条件 跨账号共享数据的先决条件&#xff08;命名资源和tag授权都需要&#xff09; 分两种情况 如果账户中没有glue data catalog资源策略&#xff0c;则LakeFormation跨账户授予将照常进行 如果存在glue d…

使用高性能NIO框架netty实现IM集群对聊方案

文章目录 前言技术积累什么是nettynetty如何实现IM如何实现IM集群 实战演示基础配置netty搭建IM集群redis发布订阅 实战测试 前言 在前面的博文中我们分享了原生websoket集群搭建&#xff0c;也用redis 发布订阅实现了集群消息正常有序分发。但是有不少同学希望风向一期netty实…

基于生命周期评价法的农田温室气体排放估算;农田CH4和N2O排放模拟;农田碳库模型和土壤呼吸等

目录 专题一 温室气体排放模拟研究 专题二 农田CH4和N2O排放模拟 专题三 农田碳库模型和土壤呼吸 专题四 基于生命周期评价法的农田温室气体排放估算 专题五-六 基于过程模型的温室气体排放模拟 专题七 案例模拟与疑难解答 更多应用 农业是甲烷&#xff08;CH4&#xff…

List基本使用(C++)

目录 1.list的介绍 2.list的使用 list的构造 list的size() 和 max_size() list遍历操作 list元素修改操作 assign()函数 push_front(),push_back 头插&#xff0c;尾插 pop_front() pop_back 头删尾删 insert()函数 swap()函数 resize()函数 clear()函数 list类数…

yolov10 瑞芯微 rknn 部署 C++代码

yolov10 目标检测rknn的C部署来了。 特别说明&#xff1a;如有侵权告知删除&#xff0c;谢谢。 直接上代码和模型&#xff0c;欢迎参考交流 【完整代码和模型】 1、rknn模型准备 pytorch转onnx&#xff0c;onnx再转rknn模型这一步就不再赘述&#xff0c;请参考上一篇 【yolov1…

TPM之VMK密封

本篇文章主要介绍基于TPM的Bitlocker全盘加密时,VMK密钥的密封(Seal)流程,至于TPM、Bitlocker、密钥保护器、VMK密钥等这些东西是什么,这里不做解释,需要自己脑补一下(╮(╯▽╰)╭)。 首先看看一张结构图(来自网络),了解一下TPM加密的基本框架与流程: 同样,基于…

关于读书,你可能没想到的陷阱、问题和思考

最近经常看到有人问&#xff1a;AI 已经这么发达了&#xff0c;如果以后的 AI 会更智能&#xff0c;那我们还有必要读书吗&#xff1f; 我认为&#xff1a;还是十分有必要的。 为什么呢&#xff1f;因为读书其实不仅仅是为了获取知识&#xff0c;它更重要的一个作用&#xff0c…

数据结构-堆排序问题

需要在数组里面进行排序&#xff0c;我们可以采取堆排序对其解决问题 版本1&#xff1a; 创建一个数组等大的堆&#xff0c;把数组里面的数值输入到堆里面进行堆排序&#xff0c;但是这样的弊端就是&#xff0c;不是顺序排序 版本2&#xff1a; 每次我们取堆顶然后打印&#xf…

3440亿!国家大基金三期正式落地,关注半导体与算力芯片!

重磅消息来了&#xff01; 5月24日&#xff0c;注册规模3,440亿元人民币的“国家集成电路产业投资基金三期股份有限公司”正式成立&#xff0c;这也意味着&#xff0c;传闻已久的**“国家大基金三期”正式落地&#xff01;** 企查查股东信息显示&#xff0c;该公司由财政部、国…