# 如何设置网络代理

#### 问题现象

如何为网络请求添加代理配置。

#### 背景知识

*   connection.setAppHttpProxy：设置应用级Http代理配置信息。
*   connection.getDefaultHttpProxy：获取网络的默认代理配置信息。
*   ProxyConfiguration：ProxyConfiguration接口允许开发者为会话中的HTTP请求配置代理设置，从而提供在系统、自定义或无代理之间进行选择的灵活性。
*   HttpProxy：网络代理配置信息。

#### 解决方案

权限声明，module.json5中配置权限声明：

使用权限：ohos.permission.INTERNET。

*   方案一：
    
    使用connection.setAppHttpProxy接口设置应用级别代理配置信息，会覆盖系统设置的代理配置信息。配置后应用内网络请求如果没有额外配置代理信息，默认执行该方法配置的代理信息。取消代理配置时，使用connection.setAppHttpProxy把host设置为空字符串，port设置为0。
    
    ```
    async setProxyStatus(host: string, port: number) {
      this.isLoading = true;
      try {
        connection.setAppHttpProxy({
          host: host,
          port: port,
          exclusionList: ['XXX']
        } as connection.HttpProxy);
        this.checkProxyStatus();
      } catch (err) {
        this.proxyEnabled = false;
        this.proxyInfo = `设置失败：${JSON.stringify(err)}`;
      } finally {
        this.isLoading = false;
      }
    }
    ```
    
    connection.getDefaultHttpProxy接口获取网络的默认代理配置信息，如果设置了全局代理，则返回全局代理配置信息。可以通过获取到的信息中host是否为空，port是否大于0，判断应用当前是否开启了网络代理。
    
    ```
    async checkProxyStatus() {
      this.isLoading = true;
      this.proxyInfo = '检测中...';
      try {
        // 获取全局代理详细信息
        let proxyDetail = await connection.getDefaultHttpProxy();
    
    
        if (proxyDetail.host.length > 0 && proxyDetail.port > 0) {
          this.proxyEnabled = true;
          this.proxyInfo = `${proxyDetail.host}:${proxyDetail.port}`;
        } else {
          this.proxyEnabled = false;
          this.proxyInfo = `...`;
        }
      } catch (err) {
        this.proxyEnabled = false;
        this.proxyInfo = `检测失败：${JSON.stringify(err)}`;
      } finally {
        this.isLoading = false;
      }
    }
    ```
    
*   方案二：
    
    为单次网络请求配置代理信息。
    
    httpRequest.request请求时，HttpRequestOptions中的usingProxy代理信息可以自定义设置，无代理或系统设置的代理配置。
    
    ```
    async testHttpProxyRequest() {
      this.isLoading = true;
      this.testResult = '请求中...';
      try {
        const httpRequest = http.createHttp();
        const response = await httpRequest.request(this.url,
          {
            usingProxy: {
              host: this.proxyUrl,
              port: this.proxyPort
            } as connection.HttpProxy
          }
        );
        if (response.responseCode === 200) {
          const result = JSON.stringify(response.result);
          this.testResult = `请求成功 .\n：${result}`;
        } else {
          this.testResult = `请求失败 .\n响应码：${response.responseCode}`;
        }
      } catch (err) {
        this.testResult = `请求异常 .\n错误信息：${JSON.stringify(err)}`;
      } finally {
        this.isLoading = false;
      }
    }
    ```
    
    rcp请求时，rcp.Configuration中的proxy代理信息允许开发者为会话中的HTTP请求配置代理设置，从而提供在系统、自定义或无代理之间进行选择的灵活性。
    
    ```
    async testRcpProxyRequest() {
      this.isLoading = true;
      this.testResult = '请求中...';
      try {
        const session = rcp.createSession();
        // 自定义proxy
        const configuration: rcp.Configuration = {
          proxy: {
            url: `${this.proxyUrl}:${this.proxyPort}`,
            createTunnel: 'always',
          }
        };
        const request = new rcp.Request(this.url, 'GET');
        request.configuration = configuration;
    
    
        session.fetch(request).then((response: rcp.Response) => {
          if (response.statusCode === 200) {
            this.testResult = `请求成功 .\n：${response}`;
          } else {
            this.testResult = `请求失败 .\n响应码：${response.statusCode}`;
          }
          session.close();
        }).catch((err: BusinessError) => {
          console.error(`The error code is ${err.code}, error message is ${JSON.stringify(err)}`);
          session.close();
        });
      } catch (err) {
        this.testResult = `请求异常 .\n错误信息：${JSON.stringify(err)}`;
      } finally {
        this.isLoading = false;
      }
    }
    ```
    
*   完整代码：
    
    ```
    import { connection } from '@kit.NetworkKit';
    import http from '@ohos.net.http';
    import { webview } from '@kit.ArkWeb';
    import { rcp } from '@kit.RemoteCommunicationKit';
    
    
    @Entry
    @Component
    struct ProxyCheckPage {
      @State proxyEnabled: boolean = false; // 是否启用代理
      url: string = 'XXX.XXX.XXX'; // 需要替换为开发者需要的请求地址
      proxyUrl: string = 'XXX.XXX.XXX.XXX'; // 需要替换为开发者需要的代理地址
      proxyPort: number = 8888; // 需要替换为开发者需要的代理端口
      @State proxyInfo: string = '未检测'; // 代理信息文本
      @State testResult: string = '未测试'; // 测试请求结果
      @State isLoading: boolean = false; // 加载状态
      webviewController: webview.WebviewController = new webview.WebviewController();
    
    
      aboutToAppear(): void {
        this.checkProxyStatus();
      }
    
    
      @Styles
      fancy() {
        .width('80%')
        .height(50)
        .enabled(!this.isLoading)
        .margin({ bottom: 15 });
      }
    
    
      build() {
        Column() {
          // 检测代理按钮
          Button('一键检测代理状态')
            .fancy()
            .backgroundColor('#007DFF')
            .fontColor(Color.White)
            .onClick(() => this.checkProxyStatus());
    
    
          // 设置代理按钮
          Button('设置应用级代理')
            .fancy()
            .backgroundColor('#007DFF')
            .fontColor(Color.White)
            .onClick(() => this.setProxyStatus(this.proxyUrl, this.proxyPort));
    
    
          // 取消代理按钮
          Button('取消应用级代理')
            .fancy()
            .backgroundColor('#007DFF')
            .fontColor(Color.White)
            .onClick(() => this.setProxyStatus('', 0));
    
    
          Text(`代理启用状态：${this.proxyEnabled ? '已启用' : '未启用'}`)
            .fontSize(16)
            .margin({ bottom: 20 });
    
    
          // 代理详细信息展示
          Text('代理详细信息：')
            .fontSize(18)
            .fontWeight(FontWeight.Medium)
            .alignSelf(ItemAlign.Start)
            .margin({ left: 40, bottom: 10 });
    
    
          Text(this.proxyInfo)
            .fontSize(14)
            .width('80%')
            .backgroundColor('#F5F7FA')
            .padding(15)
            .borderRadius(8)
            .margin({ bottom: 20 })
            .textAlign(TextAlign.Start);
    
    
          // 测试请求按钮
          Button('发起测试请求验证代理')
            .fancy()
            .backgroundColor('#36CFC9')
            .fontColor(Color.White)
            .onClick(() => this.testProxyRequest());
    
    
          // http测试请求
          Button('http请求设置代理')
            .fancy()
            .backgroundColor('#36CFC9')
            .fontColor(Color.White)
            .onClick(() => this.testHttpProxyRequest());
    
    
          //rcp测试请求按钮
          Button('rcp测试请求设置代理')
            .fancy()
            .backgroundColor('#36CFC9')
            .fontColor(Color.White)
            .onClick(() => this.testRcpProxyRequest());
    
    
          Text('测试请求结果：')
            .fontSize(18)
            .fontWeight(FontWeight.Medium)
            .alignSelf(ItemAlign.Start)
            .margin({ left: 40, bottom: 10 });
    
    
          Text(this.testResult)
            .fontSize(14)
            .width('80%')
            .backgroundColor('#F5F7FA')
            .padding(15)
            .borderRadius(8)
            .textAlign(TextAlign.Start);
        }
        .width('100%')
        .height('100%')
        .padding(20)
        .backgroundColor(Color.White)
        .justifyContent(FlexAlign.Center);
      }
    
    
      async checkProxyStatus() {
        this.isLoading = true;
        this.proxyInfo = '检测中...';
        try {
          // 获取全局代理详细信息
          let proxyDetail = await connection.getDefaultHttpProxy();
    
    
          if (proxyDetail.host.length > 0 && proxyDetail.port > 0) {
            this.proxyEnabled = true;
            this.proxyInfo = `${proxyDetail.host}:${proxyDetail.port}`;
          } else {
            this.proxyEnabled = false;
            this.proxyInfo = `...`;
          }
        } catch (err) {
          this.proxyEnabled = false;
          this.proxyInfo = `检测失败：${JSON.stringify(err)}`;
        } finally {
          this.isLoading = false;
        }
      }
    
    
      async setProxyStatus(host: string, port: number) {
        this.isLoading = true;
        try {
          connection.setAppHttpProxy({
            host: host,
            port: port,
            exclusionList: ['XXX']
          } as connection.HttpProxy);
          this.checkProxyStatus();
        } catch (err) {
          this.proxyEnabled = false;
          this.proxyInfo = `设置失败：${JSON.stringify(err)}`;
        } finally {
          this.isLoading = false;
        }
      }
    
    
      async testProxyRequest() {
        this.isLoading = true;
        this.testResult = '请求中...';
        try {
          const httpRequest = http.createHttp();
          const response = await httpRequest.request(this.url);
          if (response.responseCode === 200) {
            const result = JSON.stringify(response.result);
            this.testResult = `请求成功 .\n：${result}`;
          } else {
            this.testResult = `请求失败 .\n响应码：${response.responseCode}`;
          }
        } catch (err) {
          this.testResult = `请求异常 .\n错误信息：${JSON.stringify(err)}`;
        } finally {
          this.isLoading = false;
        }
      }
    
    
      async testHttpProxyRequest() {
        this.isLoading = true;
        this.testResult = '请求中...';
        try {
          const httpRequest = http.createHttp();
          const response = await httpRequest.request(this.url,
            {
              usingProxy: {
                host: this.proxyUrl,
                port: this.proxyPort
              } as connection.HttpProxy
            }
          );
          if (response.responseCode === 200) {
            const result = JSON.stringify(response.result);
            this.testResult = `请求成功 .\n：${result}`;
          } else {
            this.testResult = `请求失败 .\n响应码：${response.responseCode}`;
          }
        } catch (err) {
          this.testResult = `请求异常 .\n错误信息：${JSON.stringify(err)}`;
        } finally {
          this.isLoading = false;
        }
      }
      async testRcpProxyRequest() {
        this.isLoading = true;
        this.testResult = '请求中...';
        try {
          const session = rcp.createSession();
          // 自定义proxy
          const configuration: rcp.Configuration = {
            proxy: {
              url: `${this.proxyUrl}:${this.proxyPort}`,
              createTunnel: 'always',
            }
          };
          const request = new rcp.Request(this.url, 'GET');
          request.configuration = configuration;
    
    
          session.fetch(request).then((response: rcp.Response) => {
            if (response.statusCode === 200) {
              this.testResult = `请求成功 .\n：${response}`;
            } else {
              this.testResult = `请求失败 .\n响应码：${response.statusCode}`;
            }
            session.close();
          }).catch((err: BusinessError) => {
            console.error(`The error code is ${err.code}, error message is ${JSON.stringify(err)}`);
            session.close();
          });
        } catch (err) {
          this.testResult = `请求异常 .\n错误信息：${JSON.stringify(err)}`;
        } finally {
          this.isLoading = false;
        }
      }
    }
    ```