HarmonyOS鸿蒙Next中web组件在onControllerAttached中使用loadUrl添加了请求头,在onInterceptRequest中拦截的请求头中为什么没有刚刚添加的header

HarmonyOS鸿蒙Next中web组件在onControllerAttached中使用loadUrl添加了请求头,在onInterceptRequest中拦截的请求头中为什么没有刚刚添加的header web组件,在onControllerAttached中使用loadUrl添加了请求头,在onInterceptRequest中拦截的请求头中,为什么没有刚刚添加的header

4 回复

暂未复现该问题,参考解决方案demo可获取到添加的请求头

【背景知识】

Web组件拦截H5页面的网络请求有以下三种方式:

onInterceptRequest:可以拦截url并返回响应,但是获取的对象里面不包含请求体内容。

网络拦截接口(arkweb_scheme_handler.h):可以对Web组件发出的请求进行拦截,并为被拦截的请求提供自定义的响应头以及响应体,通过OH_ArkWebResourceRequest_*接口获取被拦截请求的信息。可以获取url、method、referrer、headers、resourceType等信息。

WebSchemeHandler:可以拦截指定scheme的请求,可通过WebSchemeHandlerRequest.getHttpBodyStream()方法获取POST、PUT请求的数据体,支持BYTES、FILE、BLOB、CHUNKED类型的数据。

【解决方案】

通过网络拦截接口(arkweb_scheme_handler.h)可参考官方指南:拦截Web组件发起的网络请求

通过WebSchemeHandler拦截获取请求体可参考以下代码:

import { WebNetErrorList, webview } from '@kit.ArkWeb';
import { BusinessError } from '@kit.BasicServicesKit';
import { buffer } from '@kit.ArkTS';
import { util } from '@kit.ArkTS';


@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>";

  aboutToAppear() {
    // 配置Web开启调试模式
    webview.WebviewController.setWebDebuggingAccess(true);
  }

  build() {
    Column() {
      Web({
        src: 'https://developer.huawei.com/consumer/cn/doc/harmonyos-releases-V5/releasenotes-V5',
        controller: this.controller
      })
        .onControllerAttached(() => {
          try {
            this.schemeHandler.onRequestStart((request: webview.WebSchemeHandlerRequest,
              resourceHandler: webview.WebResourceHandler) => {
              console.info("[schemeHandler] onRequestStart");
              try {
                // 可以指定请求不做拦截
                if (request.getRequestUrl().endsWith("example.com")) {
                  return false;
                }

                // 获取请求头
                let header = request.getHeader();
                for (let i = 0; i < header.length; i++) {
                  console.info("[schemeHandler] onRequestStart header:" + header[i].headerKey + " " +
                  header[i].headerValue);
                }
                // 获取请求体
                let stream = request.getHttpBodyStream();
                if (stream) {
                  stream.initialize().then(() => {
                    if (!stream) {
                      console.error('[schemeHandler] HttpBodyStream initialize failed.')
                      return;
                    }
                    let size = stream.getSize();
                    console.info(`[schemeHandler] HttpBodyStream size is ${size}`);
                    stream.read(size).then((result: ArrayBuffer) => {
                      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}`);
                    }).catch((error: BusinessError) => {
                      console.error(`[schemeHandler] HttpBodyStream read failed, message is ${error.message}`);
                    });
                  })
                } else {
                  console.info("[schemeHandler] onRequestStart has no http body stream");
                }
              } catch (error) {
                console.error(`[schemeHandler] ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
              }

              // 构造响应体返回
              let response = new webview.WebSchemeHandlerResponse();
              try {
                response.setNetErrorCode(WebNetErrorList.NET_OK);
                response.setStatus(200);
                response.setStatusText("OK");
                response.setMimeType("text/html");
                response.setEncoding("utf-8");
                response.setHeaderByName("header1", "value1", false);
              } catch (error) {
                console.error(`[schemeHandler] ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
              }

              // 调用didFinish/didFail前需要优先调用didReceiveResponse将构造的响应头传递给被拦截的请求。
              let buf = buffer.from(this.htmlData)
              try {
                if (buf.length == 0) {
                  console.info("[schemeHandler] length 0");
                  resourceHandler.didReceiveResponse(response);
                  // 如果认为buf.length为0是正常情况,则调用resourceHandler.didFinish,否则调用resourceHandler.didFail
                  resourceHandler.didFail(WebNetErrorList.ERR_FAILED);
                } else {
                  console.info("[schemeHandler] length 1");
                  resourceHandler.didReceiveResponse(response);
                  resourceHandler.didReceiveResponseBody(buf.buffer);
                  resourceHandler.didFinish();
                }
              } catch (error) {
                console.error(`[schemeHandler] ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
              }
              return true;
            })

            this.schemeHandler.onRequestStop((request: webview.WebSchemeHandlerRequest) => {
              console.info("[schemeHandler] onRequestStop");
            });

            this.controller.setWebSchemeHandler('https', this.schemeHandler);
          } catch (error) {
            console.error(`ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
          }
        })
        .javaScriptAccess(true)
        .domStorageAccess(true)
    }
  }
}

更多关于HarmonyOS鸿蒙Next中web组件在onControllerAttached中使用loadUrl添加了请求头,在onInterceptRequest中拦截的请求头中为什么没有刚刚添加的header的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


您好,为了更快速解决您的问题,并且吸引更多用户一同参与您问题的解答与讨论,建议您补全如下信息:

补全复现代码(如最小复现demo),让参与用户更快速复现您的问题;

更多提问技巧,请参考:《提问小技巧:让解答更高效》

在鸿蒙Next中,Web组件的onControllerAttached回调里通过loadUrl设置的请求头,属于初始页面加载的HTTP请求。而onInterceptRequest拦截的是页面内部后续发起的网络请求(如XHR/Fetch、iframe、资源加载等)。这两个机制作用于不同的请求阶段和类型,因此通过loadUrl设置的Header不会出现在onInterceptRequest拦截的请求头中。

在HarmonyOS Next中,Web组件的onControllerAttached回调中通过loadUrl设置的请求头,与onInterceptRequest拦截到的请求头属于不同的处理阶段,可能导致无法直接获取。

具体原因如下:

  1. loadUrl设置的请求头属于初始请求:在onControllerAttached中调用loadUrl并添加的请求头,仅作用于该次初始页面加载请求。
  2. onInterceptRequest拦截的是所有网络请求:该方法会拦截页面加载后产生的所有子资源请求(如JS、CSS、图片等),但初始的页面文档请求可能不会经过此回调,或者经过时请求头已被处理。
  3. 请求头传递限制:部分平台或场景下,初始请求的定制请求头可能不会自动传递到后续拦截的子资源请求中。

解决方案: 若需在拦截请求时统一添加请求头,建议在onInterceptRequest回调中主动为特定请求添加所需头部,例如:

onInterceptRequest(request: WebResourceRequest) {
  // 添加自定义请求头
  request.setRequestHeader("Your-Header", "Value");
  return request;
}

如需保持初始请求头,可考虑将请求头信息存储在全局或组件状态中,在onInterceptRequest内读取并复用。

回到顶部