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

文章目录

  • 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大小来控制)。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【读书】读书笔记——理科生的视角:底层逻辑+数学之美

1&#xff0c;底层逻辑1&#xff08;看清这个世界的底牌&#xff09; 刘润 著 0&#xff09;什么是底层逻辑&#xff1f; 底层逻辑是&#xff1a;事物之间共同点、变化背后不变的东西事&#xff1b;看清事物的本质&#xff0c;才能在复杂变化中从根本上解决问题。 1&#x…

红队攻防渗透技术实战流程:红队目标上线之webshell工具魔改

红队攻防免杀实战 1. 红队目标上线-Webshell免杀-源码魔改1.2 Webshell-代码混淆&流量绕过&工具原理1.2 通过对冰蝎的数据包分析:1.2魔改冰蝎-JAR反编译打包构建1.2魔改冰蝎-防识别-打乱特征指纹1.2魔改冰蝎-防查杀-新增加密协议1. 红队目标上线-Webshell免杀-源码魔改…

win10/win11 优先调用大核的电源计划性能设置

前言 大小核&#xff0c;即Intel 12代开始的P-core&#xff08;性能核&#xff0c;一般叫大核&#xff09;和E-core&#xff08;能效核&#xff0c;一般叫小核&#xff09;异核架构。说下个人理解&#xff0c;就是英特尔为了增加cpu性能&#xff0c;但是又因为架构和功耗的限制…

Kubernetes中的节点选择方法

在Kubernetes集群中&#xff0c;节点选择是一个重要的环节&#xff0c;它决定了Pod将被调度到哪个节点上运行。Kubernetes提供了多种节点选择的方法&#xff0c;以满足不同的部署需求和资源优化。本文将介绍Kubernetes中的几种节点选择方法&#xff0c;并附带相关代码示例。 目…

【吊打面试官系列】Java高并发篇 - 线程的调度策略?

大家好&#xff0c;我是锋哥。今天分享关于 【线程的调度策略?】面试题&#xff0c;希望对大家有帮助&#xff1b; 线程的调度策略? 线程调度器选择优先级最高的线程运行&#xff0c;但是&#xff0c;如果发生以下情况&#xff0c;就会终止线程的运行&#xff1a; 1、线程体…

【HarmonyOS4学习笔记】《HarmonyOS4+NEXT星河版入门到企业级实战教程》课程学习笔记(十二)

课程地址&#xff1a; 黑马程序员HarmonyOS4NEXT星河版入门到企业级实战教程&#xff0c;一套精通鸿蒙应用开发 &#xff08;本篇笔记对应课程第 19节&#xff09; P19《18.ArkUI组件-页面路由》 以访问京东页面为例&#xff0c;访问过的页面并没有消失&#xff0c;而是进入了…

Modbus协议基础

文章目录 Modbus概述Modbus TCP/IP Modbus概述 Modbus是由Modicon&#xff08;现为施耐德电气公司的一个品牌&#xff09;在1979年发明的&#xff0c;是全球第一个真正用于工业现场的应用层总线协议。 为更好地普及和推动Modbus在基于以太网上的分布式应用&#xff0c;目前施…

前缀和算法专题

应用: 计算数组中某区间的和 一. 一维前缀和[模版] 答案 二. 二维前缀和[模版] 答案 三. 寻找数组的中心下标 答案 四. 除自身以外数组的乘积 答案 五. 和为k的子数组 答案 六. 和可被k整除的子数组 答案 七. 连续数组 答案 八. 矩阵区域和 答案

wireshark抓包,丢包分析?

前言 我们都知道&#xff0c;一般流量分析设备都支持pcap回放离线分析的功能&#xff0c;但如果抓的pcap丢了包&#xff0c;会影响最终安全测试的效果。比如说竞测现场需要提供pcap包测试恶意文件的检测功能&#xff0c;如果pcap中丢包&#xff0c;可能会导致文件还原失败&…

过滤器Filter

目录 概述 Filter快速入门 概述 概念&#xff1a;Filter过滤器&#xff0c;是JavaWeb三大组件&#xff08;Servlet,Filter,Listener&#xff09;之一。 过滤器可以把对资源的请求拦截下来&#xff0c;从而实一些特殊的功能。 过滤器一般完成一些通用的操作&#xff0c;比如…

nginx文件解析漏洞测试

环境条件:ubuntu14,已安装docker,docker pull ubuntu:14.04.5 一、Nginx配置 1、使用docker启动容器&#xff1a; docker run -itd --name ubuntu -p 8088:80 ubuntu:14.04.5 2、进入容器&#xff1a; docker exec -it ubuntu /bin/bash 3、然后使用以下语句安装相关环境…

P1115 最长子段和

题目描述 给出一个长度为 &#x1d45b;n 的序列 &#x1d44e;a&#xff0c;选出其中连续且非空的一段使得这段和最大。 输入格式 第一行是一个整数&#xff0c;表示序列的长度 &#x1d45b;。 第二行有 &#x1d45b;n 个整数&#xff0c;第 &#x1d456; 个整数表示序列的…

Excel某列中有不连续的数据,怎么提取数据到新的列?

这里演示使用高级筛选的例子&#xff1a; 1.设置筛选条件 在D2单元格输入公式&#xff1a;COUNTA(A4)>0 这里有两个注意事项&#xff1a; *. 公式是设置在D2单元格&#xff0c;D1单元格保持为空&#xff0c; **. 为什么公式中选A4单元格&#xff0c;A列的第一个数据在A3…

【Linux】Linux的基本指令_3

文章目录 二、基本指令15. date16. cal16. find17. grep18. zip 和 unzip19. tar20. uname 未完待续 二、基本指令 15. date date 命令可以显示当前时间。 常用标记列表&#xff1a; %H : 小时(00…23) %M : 分钟(00…59) %S : 秒(00…61) %X : 相当于 %H:%M:%S %d : 日 (01……

Neo4j安装部署及python连接neo4j操作

Neo4j安装部署及python连接neo4j操作 Neo4j安装和环境配置 安装依赖库&#xff1a; sudo apt-get install wget curl nano software-properties-common dirmngr apt-transport-https gnupg gnupg2 ca-certificates lsb-release ubuntu-keyring unzip -y 增加Neo4 GPG key&…

C++ 程序的基本要素

一 标识符 程序中变量、类型、函数和标号的名称称标识符。 a,b,name,int,char,main,void等。 系统已有的标识符称为关键字。 常见关键字 using,namespace,void,return; int,float,double,char,bool,signed,unsignex, long,short,const,true,false,sizeof if,else,for,do,whil…

C# WPF入门学习主线篇(四)—— Button的常用属性

本期来详细介绍一下WPF中Button组件的属性都有哪些 一、准备阶段 首先&#xff0c;打开我们之前创建好的工程。 这是我们之前几期一起做过的工程&#xff0c;现在重新创建一个button&#xff0c;来熟悉一下他的属性。 选中创建的button&#xff0c;点击属性栏 二、接下来介绍…

SQL 语言:完整性约束

文章目录 概述主键 ( Primary Key ) 约束外键&#xff08;Foreign Key&#xff09;约束属性值上的约束全局约束总结 概述 数据库的完整性是指数据库正确性和相容性&#xff0c;是防止合法用户使用数据库时向数据库加入不符合语义的数据。保证数据库中数据是正确的&#xff0c;…

内网穿透初步探索实践

内网穿透初步 正常来说两台Linux设备只有在同一局域网下才可以进行互相的ssh远程登录 那么如果不在一个网段下&#xff0c;比方说一台在家里连着家里的WIFI&#xff0c;一台在学校连着实验室的WIFI&#xff0c;这种情况要想实现ssh远程登录则需要用到内网穿透 这就需要用到一…

单细胞 10X 和seurat对象学习

单细胞seurat数据的基础知识 rm(list ls()) library(Seurat) #注意这个报错 #Warning: Feature names cannot have underscores (_), replacing with dashes (-) folderslist.files(./,pattern[123]$) folders scList lapply(folders,function(folder){ CreateSeuratObject(…