在 Angular 中处理多部分响应主体 [英] Handling a multipart Response body in Angular

查看:32
本文介绍了在 Angular 中处理多部分响应主体的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 Angular 中收到一个多部分响应正文,但应用程序没有正确处理响应.事实证明,Angular 中的 HttpClient 无法正确解析多部分响应主体(请参阅 GitHub 上的此问题).

I receive a multipart response body in Angular but the application is not handling the response correctly. It turns out the HttpClient in Angular is not able to parse multipart response bodies correctly (see this issue on GitHub).

HttpClient 只是在 HttpResponse 对象的主体内返回原始多部分响应,而我想要 application/json 块来自我的 HttpResponse 对象内可访问的多部分响应.

The HttpClient simply returns the raw multipart response inside the body of the HttpResponse object while I would like to have the application/json block from the multipart response accessible inside my HttpResponse object.

如何正确处理 Angular 中的多部分响应?

How can I handle multipart response inside Angular correctly?

推荐答案

我做了一个快速而肮脏的解决方案,深受 这篇另一篇文章的启发 在 stackoverflow 上创建了一个 http 拦截器类,展示了如何解析多部分响应.拦截器从多部分响应(multipart/mixedmultipart/form-datamultipart/相关).通过映射,可以轻松地将其他内容类型的附加解析器添加到类中.

I made a quick and dirty solution heavily inspired by this other post on stackoverflow and created an http interceptor class that shows how parsing multipart responses can be done. The interceptor returns the the first 'application/json' part as the response body from a multipart response (multipart/mixed, multipart/form-data or multipart/related). Through a map additional parsers for other content types can be easily added to the class.

我会在这里分享这段代码,它可能是其他人的灵感:

I will share this code here it might be an inspiration others:

import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

@Injectable({
  providedIn: 'root',
})

export class MultipartInterceptService implements HttpInterceptor {

  private parserMap = {
    'application/json': JSON.parse,
  };

  private parseMultipart(multipart: string, boundary: string): any {
    const dataArray: string[] = multipart.split(`--${boundary}`);
    dataArray.shift();
    dataArray.forEach((dataBlock) => {
      const rows = dataBlock.split(/\r?\n/).splice(1, 4);
      if (rows.length < 1) {
        return;
      }
      const headers = rows.splice(0, 2);
      const body = rows.join('');
      if (headers.length > 1) {
        const pattern = /Content-Type: ([a-z\/+]+)/g;
        const match = pattern.exec(headers[0]);
        if (match === null) {
          throw Error('Unable to find Content-Type header value');
        }
        const contentType = match[1];
        if (this.parserMap.hasOwnProperty(contentType) === true) {
          return this.parserMap[contentType](body);
        }
      }
    });
    return false;
  }

  private parseResponse(response: HttpResponse<any>): HttpResponse<any> {
    const contentTypeHeaderValue = response.headers.get('Content-Type');
    const body = response.body;
    const contentTypeArray = contentTypeHeaderValue.split(';');
    const contentType = contentTypeArray[0];
    switch (contentType) {
      case 'multipart/related':
      case 'multipart/mixed':
      case 'multipart/form-data':
        const boundary = contentTypeArray[1].split('boundary=')[1];
        const parsed = this.parseMultipart(body, boundary);
        if (parsed === false) {
          throw Error('Unable to parse multipart response');
        }
        return response.clone({ body: parsed });
      default:
        return response;
    }
  }

  // intercept request and add parse custom response
  public intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(request)
      .pipe(
        map((response: HttpResponse<any>) => {
          if (response instanceof HttpResponse) {
            return this.parseResponse(response);
          }
        }),
      );
  }
}

代码从 Content-Type 响应标头中读取边界,并使用此边界将响应正文拆分为多个块.然后它尝试解析每个部分并从响应中返回第一个成功解析的 application/json 块.

The code reads the boundary from the Content-Type response header and splits the response body in blocks using this boundary. Then it tries to parse each part and returns the first successfully parsed application/json block from the response.

如果您有兴趣返回另一个代码块或希望在最终响应中组合多个代码块,您将需要自己的解析器或更改逻辑.这需要对代码进行一些自定义.

You would need your own parser or change the logic in case you are interested in returning another code block or in case you want to combine several code blocks in the final response. This would need some customization of the code.

注意:此代码是实验性的,目前还没有准备好进行有限的测试,使用时要小心.

NOTE: This code is experimental and limited tested so far from production ready, be careful when using it.

这篇关于在 Angular 中处理多部分响应主体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆