目录

拦截器:更丰富、更高阶的定制能力

使用拦截器可以便捷地对HTTP的请求与响应进行修改,您可以创建拦截器链,按需定制一组拦截器对网络请求/响应进行修改。Remote Communication Kit模块提供了拦截器能力,在SessionConfiguration中添加interceptors参数,传入自定义的拦截器,即可在HTTP请求和响应的过程中添加拦截器功能。

约束与限制

拦截器:更丰富、更高阶的定制能力支持Phone、2in1、Tablet、Wearable设备。并且从5.1.1(19)开始,新增支持TV设备。

拦截器工作原理

在客户端发送HTTP请求到达目标服务器之前,可以使用拦截器对请求进行修改。如下图,定义了RequestUrlChangeInterceptor链式拦截器(下文以拦截器1代替)和ResponseHeaderRemoveInterceptor链式拦截器(下文以拦截器2代替)。拦截器1会将请求先拦截,该拦截器可以实现当网络质量差时,通过修改HTTP请求中的URL,来调整请求资源的大小。然后经过拦截器2,最后到达Internet。当请求到达目标服务器,服务器返回请求响应的结果给客户端之前,可以使用拦截器对HTTP的响应进行修改。响应先被拦截器2拦截,在响应返回给应用前检查和修改服务器的响应头。然后经过拦截器1,最后客户端接收响应结果。

RequestUrlChangeInterceptor拦截器和ResponseHeaderRemoveInterceptor拦截器都是自定义拦截器,需要开发者通过代码去实现内部逻辑。

拦截器的定义和使用

本节介绍如何自定义拦截器,定义RequestUrlChangeInterceptor拦截器和ResponseHeaderRemoveInterceptor拦截器实现Interceptor,可在intercept()方法中根据业务需求自定义处理逻辑,实现对请求/响应的修改。以下示例模拟网络质量不佳的情况。

  1. 导入需要的模块,示例中包含了利用远场通信框架发起网络请求以及请求后的响应和错误处理,所以需导入以下模块。

    import { rcp } from '@kit.RemoteCommunicationKit';
    import { url } from '@kit.ArkTS';
  2. 定义两种拦截器,RequestUrlChangeInterceptor拦截器中,当网络质量较差的时候,修改请求中的URL路径,请求获取分辨率较小的图片,可提升用户体验;NetworkQualityProvider中的isNetworkFast用于在示例代码中模拟网络质量的好坏,这里仅作为场景模拟,需要开发者自行评估实现。

    // 模拟网络质量不佳的情况
    export class NetworkQualityProvider {
      public isNetworkFast: boolean = true
    
      public constructor(isNetworkFast: boolean) {
        this.isNetworkFast = isNetworkFast
      }
    }
    
    // 定义RequestUrlChangeInterceptor拦截器
    export class RequestUrlChangeInterceptor implements rcp.Interceptor {
      private readonly networkQualityProvider: NetworkQualityProvider;
    
      constructor(networkQualityProvider: NetworkQualityProvider) {
        this.networkQualityProvider = networkQualityProvider;
      }
    
      // 自定义请求处理逻辑
      async intercept(context: rcp.RequestContext, next: rcp.RequestHandler): Promise<rcp.Response> {
        if (context.request.method === 'GET' && !this.networkQualityProvider.isNetworkFast) {
          console.info('[RequestUrlChangeInterceptor]: Slow network is detected');
          const parts = context.request.url.pathname.split('.');
          if (parts.length === 2) {
            const changed = url.URL.parseURL(context.request.url.href);
            changed.pathname = parts[0] + '_small.' + parts[1];
            console.info(`[RequestUrlChangeInterceptor]: Replace URL from "${context.request.url.href}" to "${changed}"`);
            AppStorage.setOrCreate('ReplacedInfo',
              `[RequestUrlChangeInterceptor]: Replace URL from '${context.request.url.href}' to '${changed}'`);
            context.request.url = changed;
          }
        } else {
          console.info('[RequestUrlChangeInterceptor]: Network is fast');
          AppStorage.setOrCreate('ReplacedInfo', '');
        }
        return next.handle(context);
      }
    }
    
    // 定义ResponseHeaderRemoveInterceptor拦截器
    export class ResponseHeaderRemoveInterceptor implements rcp.Interceptor {
      // 自定义响应处理逻辑
      async intercept(context: rcp.RequestContext, next: rcp.RequestHandler): Promise<rcp.Response> {
        const response = await next.handle(context);
        const toReturn: rcp.Response = {
          request: response.request,
          statusCode: response.statusCode,
          httpVersion: response.httpVersion,
          headers: {
            'content-range': response.headers['content-range']
          },
          effectiveUrl: response.effectiveUrl,
          timeInfo: response.timeInfo,
          toJSON: () => null
        };
        console.info('[ResponseHeaderRemoveInterceptor]: Response was modified');
        AppStorage.setOrCreate('ReplacedResponseData',
          `[ResponseHeaderRemoveInterceptor]: Response was modified '${context.request.url.href}'`);
        return toReturn;
      }
    }
  3. 使用拦截器,通过Remote Communication Kit模块中的SessionConfiguration对象来设置interceptors,即可在请求/响应中添加拦截器。

    function httpRequest(networkStateSimulator: NetworkQualityProvider): rcp.Session {
      const sessionConfig: rcp.SessionConfiguration = {
        interceptors: [
          new RequestUrlChangeInterceptor(networkStateSimulator),
          new ResponseHeaderRemoveInterceptor()
        ],
        requestConfiguration: {
          security: {
            tlsOptions: {
              tlsVersion: 'TlsV1.3'
            }
          }
        }
      };
      const session = rcp.createSession(sessionConfig);
      return session;
    }