Сжатие исходящих запросов в Angular 2+

Я хочу использовать сжатие gzip или deflate для исходящих запросов POST и PUT JSON к проекту API из приложения Angular 4.

В настоящее время я использую 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: сдуть с соответствующими значениями Accept-Encoding.

На данный момент я уверен, что я либо делаю что-то не то, чего не понял, либо пытаюсь сделать больше, чем позволяет мне HttpClient.

1 ответ

Я только что получил эту работу сам.

Я думаю, что проблема может быть в том, как вы используете 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-Type а также Content-Encoding заголовки должны быть установлены правильно для сжатого байтового массива.
  2. использование .buffer собственность на compressedBody объект. HttpClient нужно так, чтобы он знал, что имеет дело с байтовым массивом.
  3. Ваш API должен быть достаточно умным, чтобы преобразовать байтовый массив в json на другом конце. Это обычно не обрабатывается по умолчанию.

Вам не нужно ничего сжимать самостоятельно, просто установите соответствующие заголовки, браузер делает это автоматически, используя процесс согласования с сервером, если сервер поддерживает кодировку gzip, браузер отправит закодированный запрос.

Другие вопросы по тегам