Compress Outgoing Requests in Angular 2+

倖福魔咒の 提交于 2020-04-10 03:53:50

问题


I want to use gzip or deflate compression on outgoing POST and PUT JSON requests to an API project from an Angular 4 application.

Presently, I'm using HttpClient to send the requests. I've tried using pako or zlib to generate the compressed content, but the server returns back responses indicating a bad implementation of the compression algorithm.

My POST TypeScript looks like the following:

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;
}

I've tried various permutations of deflating and gzipping the content, but nothing seems to work. I've also inspected the outgoing requests in Fiddler and verified that Fiddler could not interpret the request JSON.

I've also verified that content is being sent with Content-Type: application/json; charset=UTF-8 and Content-Encoding: deflate with appropriate Accept-Encoding values.

At this point I'm sure I'm either doing something wrong I haven't figured out, or that I'm trying to do more than what HttpClient will allow me to do.


回答1:


I've just gotten this working myself.

I think the problem may be the way you are using pako.

pako.gzip(obj) does not return a string, unless you explicitly pass that option. It returns a byte array. (Uint8Array, specifically)

The default HttpClient will try to turn this into a json string, which is wrong. I did the following:

  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);

Note a few things:

  1. The Content-Type and Content-Encoding headers need to be set correctly for a zipped byte array.
  2. the use of the .buffer property on the compressedBody object. HttpClient needs it this way so that it knows it is dealing with a byte array.
  3. Your API will need to be smart enough to convert the byte array to json on the other end. This usually isn't handled by default.



回答2:


You don't have to compress anything yourself, just set appropriate headers, browser does this automatically using negotiation process with server, if server supports gzip encoding then browser will send encoded request.



来源:https://stackoverflow.com/questions/51942451/compress-outgoing-requests-in-angular-2

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!