HarmonyOS鸿蒙Next中arkweb是否可以实现透明加解密,让加载的网页无感?
HarmonyOS鸿蒙Next中arkweb是否可以实现透明加解密,让加载的网页无感? 比如我现在有一个已经实现功能的前后端页面:前端页面明文发送账号口令给后端,后端验证后响应数据给前端页面然后展示。
我现在希望把前端页面放到鸿蒙arkweb中,我要拦截这个网页的所有请求,比如/api/login,/api/register等。
拦截到将要发送的,就把body中的数据加密,然后再发。
拦截到相应给页面的,就把body中的数据解密,然后给页面。
这个加解密的函数鸿蒙native端,前端网页,后端都有对应实现。
我这个功能请问目前可以实现吗?
文档中提到
Web组件是否支持拦截Ajax原始响应?
不支持。Web组件目前仅提供网络请求的拦截方法,无法拦截请求的响应。然而,可以通过onInterceptRequest()回调或WebSchemeHandler机制自定义响应。
无法拦截响应请求那该怎么用onInterceptRequest()回调或WebSchemeHandler机制自定义响应实现?
可以的话麻烦给一个简单的实现demo,比如发送时把账号密码都加上首部和尾部都加上###做“加密”,解密时前后的###去掉做“解密”,这个该如何实现?
更多关于HarmonyOS鸿蒙Next中arkweb是否可以实现透明加解密,让加载的网页无感?的实战教程也可以访问 https://www.itying.com/category-93-b0.html
开发者您好,您可参考以下方案:
可以通过setWebSchemeHandler拦截网页中所有请求,包含axios请求,拦截后进行加解密操作,通过rcp或则http重新构造请求,请求服务端,或则响应后进行解密,返回给网页。示例代码可参考如下:
import { WebNetErrorList, webview } from '@kit.ArkWeb';
import { BusinessError } from '@kit.BasicServicesKit';
import { JSON, util } from '@kit.ArkTS';
import { rcp } from '@kit.RemoteCommunicationKit';
@Entry
@Component
struct WebComponent {
controller: webview.WebviewController = new webview.WebviewController();
schemeHandler: webview.WebSchemeHandler = new webview.WebSchemeHandler();
htmlData: string = '<html><body bgcolor="white">Source:<pre>source</pre></body></html>';
build() {
Column() {
Web({
// 使用时请替换为真实url
src: 'https://www.example.com',
controller: this.controller
})
.onControllerAttached(() => {
try {
this.schemeHandler.onRequestStart((request: webview.WebSchemeHandlerRequest,
resourceHandler: webview.WebResourceHandler) => {
console.info('[schemeHandler] onRequestStart');
// 判断哪些请求不拦截,可以根据url或其他条件进行判断
if (!request.getRequestUrl().startsWith('https://www.example.com')) {
return false;
}
// 对拦截请求进行处理
this.interceptRequest(request, resourceHandler);
return true;
});
this.schemeHandler.onRequestStop((request: webview.WebSchemeHandlerRequest) => {
console.info('[schemeHandler] onRequestStop, url:' + request.getRequestUrl());
});
this.controller.setWebSchemeHandler('https', this.schemeHandler);
} catch (error) {
console.error(`ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}`);
}
})
.javaScriptAccess(true)
.domStorageAccess(true)
.fileAccess(true)
.geolocationAccess(false);
};
}
private async interceptRequest(request: webview.WebSchemeHandlerRequest,
resourceHandler: webview.WebResourceHandler) {
// 此处对不放行的所有请求进行拦截。拦截后,可使用rcp或则http发送请求,获取响应后,封装响应返回web。
let body: string | undefined;
if (request.getRequestMethod() == 'POST') {
try {
body = await this.getHttpBody(request);
// 请求体不为空,可以对body做加密,如:
// body = '###' + body + '###';
} catch (error) {
console.error(`[schemeHandler] ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}`);
}
}
let header = request.getHeader();
let headerMap = new Map<string, string>();
for (let i = 0; i < header.length; i++) {
console.info('[schemeHandler] onRequestStart header:' + header[i].headerKey + ' ' + header[i].headerValue);
headerMap.set(header[i].headerKey, header[i].headerValue);
}
let headers: rcp.RequestHeaders = JSON.parse(JSON.stringify(headerMap)) as rcp.RequestHeaders;
// 使用rcp发送请求
const session = rcp.createSession();
let req = new rcp.Request(request.getRequestUrl(), request.getRequestMethod(), headers, body);
session.fetch(req).then((response) => {
console.info(`Succeeded in getting the response ${response}`);
// 构造响应体返回
let webResponse = new webview.WebSchemeHandlerResponse();
try {
webResponse.setNetErrorCode(WebNetErrorList.NET_OK);
webResponse.setStatus(200);
webResponse.setStatusText('OK');
webResponse.setMimeType('text/html');
webResponse.setEncoding('utf-8');
webResponse.setHeaderByName('header1', 'value1', false);
} catch (error) {
console.error(`[schemeHandler] ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}`);
}
// 调用didFinish/didFail前需要优先调用didReceiveResponse将构造的响应头传递给被拦截的请求。
try {
console.info('[schemeHandler] length 1');
resourceHandler.didReceiveResponse(webResponse);
// 这里可以对响应体进行解密
resourceHandler.didReceiveResponseBody(response.body);
resourceHandler.didFinish();
} catch (error) {
console.error(`[schemeHandler] ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}`);
}
}).catch((err: BusinessError) => {
console.error(`err: err code is ${err.code}, err message is ${JSON.stringify(err)}`);
});
}
private async getHttpBody(request: webview.WebSchemeHandlerRequest): Promise<string | undefined> {
let stream = request.getHttpBodyStream();
if (stream) {
await stream.initialize();
if (!stream) {
console.error('[schemeHandler] HttpBodyStream initialize failed.');
return;
}
let size = stream.getSize();
console.info(`[schemeHandler] HttpBodyStream size is ${size}`);
let result = await stream.read(size);
console.info(`[schemeHandler] HttpBodyStream buffer length is ${result.byteLength}`);
// 从buffer中转换请求体内容
let decoder = util.TextDecoder.create('utf-8');
let requestBodyStr = decoder.decodeToString(new Uint8Array(result));
console.info(`[schemeHandler] HttpBodyStream requestBody is ${requestBodyStr}`);
return requestBodyStr;
} else {
console.info('[schemeHandler] onRequestStart has no http body stream');
return undefined;
}
}
}
如果不能满足您的要求,麻烦您提供下以下信息:
请问您是在arkweb实现透明加解密,让加载的网页无感的业务场景中使用该能力,交互流程是怎样的,比如:服务器接收密码的时候怎么处理,在哪一个环节遇到了问题?您是希望基于arkweb提供能力,还是希望联合其他模块来实现呢?方便说明能力不满足可能带来的影响:什么时间用到?是否高频?有无三方库可以做到?若提供该能力,是否会造成大工作量返工?请您注意提供的内容不要包含您或第三方的非公开信息,如给您带来不便,敬请谅解。
更多关于HarmonyOS鸿蒙Next中arkweb是否可以实现透明加解密,让加载的网页无感?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
不是很了解 插眼学习一下
web组件貌似没有这么高级的功能。。。。
用https协议
什么意思?请指点
找HarmonyOS工作还需要会Flutter技术的哦,有需要Flutter教程的可以学学大地老师的教程,很不错,B站免费学的哦:https://www.bilibili.com/video/BV1S4411E7LY/?p=17,
网站服务器用https协议部署网站
https/ssl/tls不满足项目要求,需要在这个基础上再加一层国密,或者要自己实现https……
WebSchemeHandler 自定义协议 这种方式通过自定义协议(如app://)完全接管请求,更灵活,但需要修改网页代码中的请求URL。

网页本身没有鸿蒙arkweb也要求能正常运行,不能用自定义的。
然后http协议拦截好像不太行……
ArkWeb目前不支持透明加解密功能。加载的网页内容无法在用户无感知的情况下自动进行加解密处理。
根据你描述的需求,在HarmonyOS Next的ArkWeb中实现网页请求和响应的透明加解密是可行的,但需要采用特定的方法。
核心思路是:既然无法直接拦截并修改原始响应,我们可以通过拦截请求并返回自定义响应的方式来“模拟”整个请求-响应流程,在这个过程中完成加解密。
实现方案分析
文档明确指出,onInterceptRequest() 或 WebSchemeHandler 无法拦截响应,但可以自定义响应。这正是关键所在。我们可以:
- 拦截所有需要处理的网络请求(如
/api/*)。 - 在Native端(ArkTS)接管这个请求,而不是让WebView直接发往服务器。
- 在Native端:
- 对请求体进行加密。
- 使用ArkTS的网络能力(如
http模块)重新发起加密后的请求到真实后端。 - 获取后端返回的加密响应。
- 对响应体进行解密。
- 将解密后的数据,构造为一个自定义的
WebResourceResponse,直接返回给WebView中的页面。
这样,对于网页中的JavaScript来说,它发起了一个普通请求,并收到了一个“明文”响应,整个过程是无感的。加解密逻辑完全在ArkTS侧完成。
简单实现示例(概念代码)
以下是一个基于 onInterceptRequest() 的简化示例,演示如何为 /api/login 路径实现“添加/去除###”的加解密逻辑:
// 在ArkTS的Web组件中使用
import web_webview from '@ohos.web.webview';
import http from '@ohos.net.http';
import { BusinessError } from '@ohos.base';
@Entry
@Component
struct Index {
controller: web_webview.WebviewController = new web_webview.WebviewController();
aboutToAppear() {
// 设置请求拦截回调
this.controller.onInterceptRequest((request: web_webview.WebResourceRequest) => {
let url = request.requestUrl.toString();
// 1. 判断是否需要拦截(例如所有/api/开头的请求)
if (url.indexOf('/api/') !== -1) {
// 2. 接管请求,返回一个Promise,我们将提供自定义响应
return new Promise((resolve, reject) => {
this.handleInterceptedRequest(request).then((customResponse: web_webview.WebResourceResponse) => {
// 5. 将处理好的自定义响应返回给WebView
resolve(customResponse);
}).catch((err: BusinessError) => {
// 出错时,可以返回一个错误响应或拒绝Promise让请求继续
reject(err);
});
});
}
// 对于不需要拦截的请求,返回null,WebView会正常处理
return null;
});
}
// 3. 处理被拦截的请求
async handleInterceptedRequest(request: web_webview.WebResourceRequest): Promise<web_webview.WebResourceResponse> {
// 假设是POST请求,获取请求体(这里需要根据实际请求方法处理)
let requestBody: string = ''; // 实际应从request中获取请求体,可能需要异步读取
// 注意:获取原始请求体可能涉及流处理,此处为简化示例。
// 模拟“加密”:在body首尾添加###
let encryptedBody = `###${requestBody}###`;
// 4. 使用ArkTS的http模块,向真实后端发送加密后的请求
let httpRequest = http.createHttp();
let options: http.HttpRequestOptions = {
method: http.RequestMethod.POST, // 保持原方法
header: request.requestHeaders, // 传递原始headers
extraData: encryptedBody, // 发送加密后的body
readTimeout: 60000,
connectTimeout: 60000
};
try {
let response = await httpRequest.request(request.requestUrl.toString(), options);
// 获取后端返回的加密响应体
let encryptedResponseBody = await response.result.toString();
// 模拟“解密”:去掉首尾的###
let decryptedResponseBody = encryptedResponseBody.replace(/^###|###$/g, '');
// 构造自定义响应返回给WebView
let customResponse: web_webview.WebResourceResponse = {
responseData: decryptedResponseBody, // 解密后的数据
responseHeaders: response.header, // 使用后端返回的headers
responseMimeType: 'application/json', // 根据实际情况设置
responseEncoding: 'utf-8',
statusCode: response.responseCode,
reasonPhrase: 'OK'
};
return customResponse;
} catch (error) {
// 错误处理
console.error(`Request failed: ${JSON.stringify(error)}`);
throw error;
} finally {
httpRequest.destroy();
}
}
build() {
Column() {
Web({ src: 'www.example.com/yourpage.html', controller: this.controller })
.width('100%')
.height('100%')
}
}
}
关键点与注意事项
- 请求体获取:上述示例中
requestBody的获取是简化的。实际应用中,如果请求体是表单数据或JSON,你需要从WebResourceRequest对象中正确提取,这可能涉及处理请求流。 - 性能考量:拦截所有API请求并在Native端中转,会增加一定的延迟和Native端的处理负担。需评估对性能的影响。
- 错误处理:必须做好全面的错误处理(网络错误、加解密失败、解析失败等),并向WebView返回适当的错误响应(如4xx, 5xx状态码),否则网页逻辑可能异常。
- Header处理:示例中简单传递了原始请求头。实际可能需要过滤或修改某些Header(如
Content-Length需要重新计算)。 WebSchemeHandler:对于更复杂或需要更精细控制的场景(如自定义协议myapp://api/),可以使用WebSchemeHandler。其原理类似,注册自定义协议处理器,完全由ArkTS侧接管该协议下所有资源的请求与响应,实现方式更为彻底。
总结
你的需求可以通过 “拦截请求 -> Native端代理请求并加解密 -> 返回自定义响应” 的模式在HarmonyOS Next的ArkWeb中实现。虽然不能直接修改原始响应流,但通过返回一个全新的、处理过的响应,可以达到让网页无感加解密的最终效果。示例代码提供了使用 onInterceptRequest() 的基本框架,你需要根据实际的请求体格式、加解密算法和错误处理逻辑进行完善。

