在Angular 2+中压缩发送的请求

7
我希望在来自Angular 4应用程序的API项目的传出POST和PUT JSON请求上使用gzip或deflate压缩。目前,我正在使用HttpClient发送这些请求。我已经尝试使用pako或zlib生成压缩内容,但服务器返回的响应表明压缩算法的实现有问题。我的POST TypeScript代码如下:

public post(url: string, content: any): Observable < any > {
  const fullUrl: string = `${HttpService.baseUrl}/${url}`;

  Logger.debug(`Beginning HttpPost invoke to ${fullUrl}`, content);

  // Optionally, deflate the input
  const toSend: any = HttpService.compressInputIfNeeded(content);

  return Observable.create((obs: Observer < any > ) => {
    this.client.post(fullUrl, toSend, HttpService.getClientOptions()).subscribe(
      (r: any) => {
        Logger.debug(`HttpPost operation to ${fullUrl} completed`, r);

        // Send the response along to the invoker
        obs.next(r);
        obs.complete();
      },
      (err: any) => {
        Logger.error(`Error on HttpPost invoke to ${fullUrl}`, err);

        // Pass the error along to the client observer
        obs.error(err);
      }
    );
  });
}

private static getClientOptions(): {
  headers: HttpHeaders
} {
  return {
    headers: HttpService.getContentHeaders()
  };
}

private static getContentHeaders(): HttpHeaders {
  let headers: HttpHeaders = new HttpHeaders({
    'Content-Type': 'application/json; charset=utf-8'
  });

  // Headers are immutable, so any set operation needs to set our reference
  if (HttpService.deflate) {
    headers = headers.set('Content-Encoding', 'deflate');
  }
  if (HttpService.gzip) {
    headers = headers.set('Content-Encoding', 'gzip');
  }

  return headers;
}

private static compressInputIfNeeded(content: any): string {
  const json: string = JSON.stringify(content);

  Logger.debug('Pako Content', pako);

  if (HttpService.deflate) {
    const deflated: string = pako.deflate(json);
    Logger.debug(`Deflated content`, deflated);

    return deflated;
  }

  if (HttpService.gzip) {
    const zipped: string = pako.gzip(json);
    Logger.debug(`Zipped content`, zipped);

    return zipped;
  }

  return json;
}

我尝试了各种排列组合的方法来压缩和解压内容,但是似乎都不起作用。我还在 Fiddler 中检查了发出的请求并验证了 Fiddler 无法解释请求的 JSON 数据。
我还验证了内容是以 Content-Type: application/json; charset=UTF-8 和 Content-Encoding: deflate 的方式发送,并带有适当的 Accept-Encoding 值。
目前,我确定要么是我做错了什么还没有弄清楚,要么就是我试图做超出 HttpClient 允许范围的事情。
1个回答

11
我刚刚自己解决了这个问题。我认为问题可能是你使用pako库的方式不对。pako.gzip(obj)默认返回一个字节数组(Uint8Array类型),而不是字符串,除非你显式传递该选项。默认的HttpClient会尝试将其转换为json字符串,这是错误的。我采用了以下方法:
  const newHeaders: Headers = new Headers();
  newHeaders.append('Content-Encoding', 'gzip')
  newHeaders.set('Content-Type', 'application/octet-stream');

  var options = { headers: newHeaders, responseType: ResponseContentType.Json };

  var compressedBody = pako.gzip(JSON.stringify(body))

  client.post(url, compressedBody.buffer, options);

请注意以下几点:

  1. 对于压缩的字节数组,需要正确设置Content-TypeContent-Encoding头。
  2. compressedBody对象上的.buffer属性必须被使用。这是因为HttpClient需要以这种方式处理它才能知道它正在处理一个字节数组。
  3. 您的API需要足够智能,在另一端将字节数组转换为json格式。通常这不会被默认处理。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接