转载:https://www.cnblogs.com/sinceret/p/10417941.html

转载:https://stackoverflow.com/questions/48811756/registering-custom-backend-scheme-is-not-working-in-cef

转载:https://www.twblogs.net/a/5c308e03bd9eee35b3a4d59a/zh-cn

转载:http://www.voidcn.com/article/p-ffanxazs-bpp.html

转载:https://magpcss.org/ceforum/viewtopic.php?f=6&t=13266

转载:https://github.com/gabyx/ExecutionGraph/tree/3ff8b340d3ae1c87976104f0bbbda4c048e7eb2b(Github上Demo)

转载:https://blog.csdn.net/ming19951224/article/details/81807159(解决思路参考)

转载:https://blog.csdn.net/cdx1170776994/article/details/76571535

转载:https://blog.csdn.net/zhangpeng_linux/article/details/85858814

转载:https://www.cnblogs.com/himax/p/how_to_intercept_response_in_cef_using_csharp.html

在谷歌浏览器中点击设置,地址栏里出现的不是普通网址,而是chrome://settings/,这个地址就是谷歌浏览器的自定义scheme,cef也提供了自定义协议手段。

scheme就是一种协议,比如http://helloworld.com中的http就是scheme,不过它是内置的。client://helloworld.com中的client就是一个自定义scheme。

当javascript通过XMLHttpRequest请求地址client://helloworld.com时,我们c++中实现的处理器,就会收到这个请求。

XMLHttpRequest可以通过post方法将二进制数据如arraybuffer发送到browser进程。
1.当javascript需要传递大量二进制数据给browser进程的c++代码时,可以使用POST方法,
2.当javascript需要从browser进程的c++代码拿到大量二进制数据时,可以使用GET方法。

1.CEF注册custom scheme 来接受http请求

在cef中我们可以通过以下接口来注册scheme

bool CefRegisterSchemeHandlerFactory(
const CefString& scheme_name,
const CefString& domain_name,
CefRefPtr<CefSchemeHandlerFactory> factory);

注册一个自定义http scheme

CefRegisterSchemeHandlerFactory("http", "test", new MySchemeHandlerFactory());

这个scheme限定了,scheme为"http",domain为"test",只有当请求为"http://test/"开头时,才会执行自定义c++代码。

处理器工厂为MySchemeHandlerFactory,是我们自己实现的处理请求的c++代码。

继承一个工厂类MySchemeHandlerFactory : public CefSchemeHandlerFactory

需要包含#include "include/cef_scheme.h"

.h文件

#ifndef _MYSCHEMEHANDLERFACTORY_H_
#define _MYSCHEMEHANDLERFACTORY_H_
#include "include\cef_scheme.h" class MySchemeHandlerFactory : public CefSchemeHandlerFactory
{
public:
virtual CefRefPtr<CefResourceHandler> Create(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
const CefString& scheme_name,
CefRefPtr<CefRequest> request)
OVERRIDE;// Return a new resource handler instance to handle the request. private:
IMPLEMENT_REFCOUNTING(MySchemeHandlerFactory);
}; #endif //_MYSCHEMEHANDLERFACTORY_H_

.cpp文件

#include "MySchemeHandlerFactory.h"
#include "MyResourceHandler.h"
#include "include/cef_parser.h"
#include "include/wrapper/cef_helpers.h"
#include "include/wrapper/cef_stream_resource_handler.h"
#include <shlwapi.h>
#pragma comment(lib, "shlwapi.lib") CefRefPtr<CefResourceHandler> MySchemeHandlerFactory::Create(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
const CefString& scheme_name,
CefRefPtr<CefRequest> request)
{
CEF_REQUIRE_IO_THREAD(); CefString url = request->GetURL();
cef_uri_unescape_rule_t unescape_rule = UU_SPACES;//处理路径中有空格
CefString& decoded_value = CefURIDecode(url, true, unescape_rule); CefURLParts urlParts;
if (CefParseURL(url, urlParts))
{
std::wstring filePath = CefURIDecode(CefString(&urlParts.query),true,unescape_rule);//处理有中文路径
CefRefPtr<CefStreamReader> fileStream = CefStreamReader::CreateForFile(CefString(filePath)); if (fileStream != nullptr)
{
// "ext" 获取扩展名 例如:"txt"、"jpg"
std::wstring ext;
ext = PathFindExtension(filePath.c_str());
ext =ext.substr(, ext.length());
CefString mimeType(CefGetMimeType(ext));
//todo: Complete known mime times with web-font extensions
if (mimeType.empty())
{
//mimeType = "font/" + fileExtension;
} return CefRefPtr<CefStreamResourceHandler>(new CefStreamResourceHandler(mimeType, fileStream));//以二进制流的方式把文件返给js并显示到html标签中
}
} return new MyResourceHandler();
}

2.继承一个资源类class MyResourceHandler : public CefResourceHandler

ProcessRequest 处理请求,允许请求返回true;取消请求返回false。当需要返回的数据就绪后(自行请求网络或者文件就绪)或立即调用callback.Continue(),通知cef进入下一步:GetResponseHeaders。

GetResponseHeaders 设置响应头,在这里可以设置mime-type,响应长度,其它头等。不确定长度设置响应长度为-1。

ReadResponse 设置响应结果。可以设置响应具体内容,设置已读取长度。cef调用完上一步后会继续调用此方法。根据响应长度和数据就绪情况,调用此方法的次数和策略不同。

当响应长度为-1时,cef无法根据已读长度确定是否已读取完毕,必需根据返回值false来结束读取。

当响应长度大于0时,cef根据每次调用得到的已读长度,或返回值false来结束读取。

如果数据未就绪,可以设置读取长度为0 ,返回true,并在稍后调用callbak.Continue()通知cef调用此方法读取响应内容。

注意:

当响应长度为-1时,必需保证此方法至少执行两次,第一次返回true表示数据全部就绪,第二次返回false表示读取结束。

当响应长度大于0时,设置内容和已读长度,返回true。则此方法只执行一次。

若实际返回的响应内容,长度大于之前设置的响应总长度,则返回内容将被截取。

#ifndef _MYRESOURCEHANDLER_H_
#define _MYRESOURCEHANDLER_H_
#include <fstream>
#include <stdio.h>
#include "include\cef_resource_handler.h" class MyResourceHandler : public CefResourceHandler
{
public:
MyResourceHandler(); virtual bool ProcessRequest(CefRefPtr<CefRequest> request,
CefRefPtr<CefCallback> callback)OVERRIDE; virtual void GetResponseHeaders(CefRefPtr<CefResponse> response,
int64& response_length,
CefString& redirectUrl) OVERRIDE; virtual void Cancel() OVERRIDE{
// Cancel the response...
} virtual bool ReadResponse(void* data_out,
int bytes_to_read,
int& bytes_read,
CefRefPtr<CefCallback> callback)
OVERRIDE; virtual bool CanGetCookie(const CefCookie& cookie); virtual bool CanSetCookie(const CefCookie& cookie); private:
std::string data_;
IMPLEMENT_REFCOUNTING(MyResourceHandler);
};
#endif//_MYRESOURCEHANDLER_H_

.cpp文件

#include "MyResourceHandler.h"

MyResourceHandler::MyResourceHandler()
{ } bool MyResourceHandler::ProcessRequest(CefRefPtr<CefRequest> request,
CefRefPtr<CefCallback> callback)
{
std::string url = request->GetURL(); data_ = "hello cef";//返回到页面中的内容
callback->Continue();//这个一定要有
return true;//
} void MyResourceHandler::GetResponseHeaders(CefRefPtr<CefResponse> response,
int64& response_length,
CefString& redirectUrl) { response->SetMimeType("text/plain");
response->SetStatus();
response_length = data_.length();
} bool MyResourceHandler::ReadResponse(void* data_out,
int bytes_to_read,
int& bytes_read,
CefRefPtr<CefCallback> callback)
{
int size = static_cast<int>(data_.length());
memcpy(data_out, data_.c_str(), size);
bytes_read = size;
return true;
} bool MyResourceHandler::CanGetCookie(const CefCookie& cookie)
{
return false;
} bool MyResourceHandler::CanSetCookie(const CefCookie& cookie)
{
return false;
}

3.在初始化cef那几行代码后面增加一句

CefRegisterSchemeHandlerFactory("http", "test", new MySchemeHandlerFactory());
CefSettings cSettings;
const char* loc = "zh-CN"; cSettings.no_sandbox = true;
cSettings.multi_threaded_message_loop = true;
//cSettings.single_process = false;
cSettings.log_severity = LOGSEVERITY_DISABLE;//设置日志级别,解决安装启动佰卓数安后桌面出现一个debug.log文件(调试阶段可以去掉)
CefString(&cSettings.locale).FromASCII(loc);
cef_string_from_ascii(loc, strlen(loc), &cSettings.locale); // Execute the secondary process, if any.
CefInitialize(main_args, cSettings, spApp.get(), sandbox_info);
/***************************************结束初始化cef*******************************************/
//自定义scheme
CefRegisterSchemeHandlerFactory("http", "test", new MySchemeHandlerFactory());

4.CEF浏览器加载的静态html

 <html>
<script>
function do_post()
{
//alert('posting');
var xhr = new XMLHttpRequest();
var zurl = "http://test?C:\\Users\\Administrator\\Desktop\\梅西.jpg";
xhr.open("GET", zurl, true);
xhr.responseType = 'blob';
xhr.onload = function()
{
//console.log(this);
if (this.status == 200)
{
var blob = this.response;
var img = document.createElement("img");
img.onload = function(e) {
window.URL.revokeObjectURL(img.src);
};
//alert(blob);
img.src = window.URL.createObjectURL(blob);
document.body.appendChild(img);
}
}
xhr.send();
//alert('posted');
} function do_video()
{
//alert('posting');
var xhr = new XMLHttpRequest();
var zurl = "http://test?C:\\Users\\Administrator\\Desktop\\稻香.mp4";
xhr.open("GET", zurl, true);
xhr.responseType = 'blob';
xhr.onload = function()
{
//console.log(this);
if (this.status == 200)
{
var blob = this.response;
var video = document.querySelector("video");
//alert(window.URL.createObjectURL(blob));
video.src = window.URL.createObjectURL(blob); }
}
xhr.send();
//alert('posted');
} function do_audio()
{
//alert('posting');
var xhr = new XMLHttpRequest();
var zurl = "http://test?C:\\Users\\Administrator\\Desktop\\千年等一回.mp3";
xhr.open("GET", zurl, true);
xhr.responseType = 'blob';
xhr.onload = function()
{
//console.log(this);
if (this.status == 200)
{
var blob = this.response;
var audio = document.querySelector("audio");
//alert(window.URL.createObjectURL(blob));
audio.src = window.URL.createObjectURL(blob); }
}
xhr.send();
//alert('posted');
} </script>
<body onLoad="">
<div>
<!-- <img src="图片路径、地址" alt="" /> -->
<input type="button" value="加载图片" onclick="do_post()">
<input type="button" value="加载视频" onclick="do_video();">
<input type="button" value="加载音频" onclick="do_audio();">
</div>
<video controls="true" ></video>
<audio controls="true" ></audio>
<p>Hello everyone!
</p>
</body>
</html>

CEF 自定义用户协议(scheme)实现以二进制流的方式显示图片、视频、音频的更多相关文章

  1. 【转载】C#将图片以二进制流的方式存入数据库

    在C#开发应用程序的过程中,图片一般会存放在文件系统中,当然图片也可以二进制的方式存放到数据库中,不过一般不建议存放在数据库中,因为图片占用的空间还是挺大的,特殊情况下可以考虑将图片存在数据.此文将介 ...

  2. python+ mysql存储二进制流的方式

    很多时候我们为了管理方便会把依稀很小的图片存入数据库,有人可能会想这样会不会对数据库造成很大的压力,其实大家可以不用担心,因为我说过了,是存储一些很小的图片,几K的,没有问题的! 再者,在这里我们是想 ...

  3. [转]Windows 注册自定义的协议

    [转自] http://blog.sina.com.cn/s/blog_86e4a51c01010nik.html 1.注册应用程序来处理自定义协议 你必须添加一个新的key以及相关的value到HK ...

  4. 自定义URL协议在Web中启动本地应用程序

    转自(http://blog.csdn.net/jackychen_king/article/details/7743811) 1.注册应用程序来处理自定义协议 你必须添加一个新的key以及相关的va ...

  5. TeamTalk自定义IM协议的理解

    一.TeamTalk自定义IM协议 TeamTalk自定义IM协议是一种基于protocol buffer的消息传递协议,protocol buffer可以自定义消息格式.protocol buffe ...

  6. 网络协议 22 - RPC 协议(下)- 二进制类 RPC 协议

        前面我们认识了两个常用文本类的 RPC 协议,对于陌生人之间的沟通,用 NBA.CBA 这样的缩略语,会使得协议约定非常不方便.     在讲 CDN 和 DNS 的时候,我们讲过接入层的设计 ...

  7. asp.net core系列 47 Identity 自定义用户数据

    一.概述 接着上篇的WebAppIdentityDemo项目,将自定义用户数据添加到Identity DB,自定义扩展的用户数据类应继承IdentityUser类, 文件名为Areas / Ident ...

  8. Keycloak 13 自定义用户身份认证流程(User Storage SPI)

    Keycloak 版本:13.0.0 介绍 Keycloak 是为现代应用程序和服务提供的一个开源的身份和访问管理的解决方案. Keycloak 在测试环境可以使用内嵌数据库,生产环境需要重新配置数据 ...

  9. Newtonsoft.Json 自定义 解析协议

    在开发web api的时候 遇到一个要把string未赋值默认为null的情况改成默认为空字符串的需求 这种情况就需要自定义json序列话的 解析协议了 Newtonsoft.Json默认的解析协议是 ...

随机推荐

  1. ide phpStorm使用git的命令行工具

    1.点击phpStorm左下角,点击terminal 2.发现是windows自带的cmd.exe,可以将其改为git的sh.exe 3.打开设置(File -> Settings -> ...

  2. 20164320 王浩 Exp1 PC平台逆向破解

    一.逆向及Bof基础实践说明 1.1实践目标 本次实践的对象是一个名为pwn1的linux可执行文件. 该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串. 手工修 ...

  3. 为什么vue里面data里面的对象,无法用delete删除属性

    因为vue里面的data是用get赋值的,所以无法用delete, 这时你可以用Object.defineProperty() Object.defineProperty(basic,'photo', ...

  4. 微信小程序wx.getLocation()获取经纬度及JavaScript SDK调用腾讯地图API获取某一类地址

    简介 腾讯位置服务为微信小程序提供了基础的标点能力.线和圆的绘制接口等地图组件和位置展示.地图选点等地图API位置服务能力支持,使得开发者可以自由地实现自己的微信小程序产品. 在此基础上,腾讯位置服务 ...

  5. netty例子

    流式编程 客户端 这里MessageToByteEncoder继承于outchanel 服务端

  6. javascript的ES6学习总结(第一部分)

    ES6(ESNext学习总结——第一部分) ES6, 全称 ECMAScript 6.0 ,是 JavaScript 的下一个版本标准,2015.06 发版. ECMA每年6月份,发布一个版本 201 ...

  7. git提交到一半关闭时

    一:出现问题 最近写东西,在提交代码时,突然出现一大推文件... 忘记加.gitignore文件了,导致所有的安装依赖也都上传了.所以,点击了关闭按钮,当下一次提交时,出现了错误. Another g ...

  8. Dapper的应用

    Dapper是一个轻型的开源ORM类,代码就一个SqlMapper.cs文件 using Dapper; using System; using System.Collections.Generic; ...

  9. android模拟器访问PC本地接口

    一般来讲PC本地接口是localhost:8080 而在安卓模拟器上用的话,他会映射模拟器本身的,也就是说,可以把模拟器也当成一个PC端来看待,这样会好理解点吧 而在模拟器上想要访问PC本地的loca ...

  10. 初识STL vector

    写这个主要是当作笔记来写的,配上自己的理解加上一些测试示例; 上代码: #include<iostream>#include<cstring>#include<vecto ...