首页 > 解决方案 > 为什么 request.ts 中的 serializeBody 方法在 case 字符串中不转换 JSON.stringify(this.body)?

问题描述

当我将string值传递给 post 方法时,该值未转换JSON。所以我们无法在 Controller 中得到这个值。

我检查了以下代码并找到了未转换值的原因。

关联

但我无法理解这种行为是正确的。

apply(id: string): Observable<boolean> {
    return this.http.post<boolean>(
      REQUEST_URL + '/applicationrequest',
      id,
      HEADERS
    );
  }
@ResponseBody
    @RequestMapping(value = "/applicationrequest", method = RequestMethod.POST)
    public boolean apply(@RequestBody UUID id) {
        return usecase.apply(id);
    }

我想知道为什么string不应该JSON自动转换的原因。如果使用方式httpClient,我想知道正确的使用方式。谢谢你。

角度版本是 8.1.0。Java 是 Java 8。Spring 是 5.1 / Spring Boot 2.1

标签: angularangular-httpclient

解决方案


我团队中的某个人也发现了这个问题,我们需要JSON.stringify(...)为所有只接受正文中的字符串的 HTTP PUT/POST 方法添加。我们生成的代理(我们使用 Swagger)没有为我们添加这个。

实际问题在Angular 代码中:

/**
* Transform the free-form body into a serialized format suitable for
* transmission to the server.
*/
serializeBody(): ArrayBuffer | Blob | FormData | string | null {
    // If no body is present, no need to serialize it.
    if (this.body === null) {
        return null;
    }
    // Check whether the body is already in a serialized form. If so,
    // it can just be returned directly.
    if (isArrayBuffer(this.body) || isBlob(this.body) || isFormData(this.body) ||
        typeof this.body === 'string') {
        return this.body;
    }
    // Check whether the body is an instance of HttpUrlEncodedParams.
    if (this.body instanceof HttpParams) {
        return this.body.toString();
    }
    // Check whether the body is an object or array, and serialize with JSON if so.
    if (typeof this.body === 'object' || typeof this.body === 'boolean' ||
        Array.isArray(this.body)) {
        return JSON.stringify(this.body);
    }
    // Fall back on toString() for everything else.
    return (this.body as any).toString();
}

普通字符串将使用最后一个选项,并将呈现为纯字符串,而不是通过JSON.stringify.

我创建了一个HTTP 拦截器来检查内容类型,如果它设置为application/jsonortext/json并且正文是纯字符串,则拦截器调用JSON.stringify以确保它是有效的 JSON 字符串。这个拦截器看起来像这样:

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

@Injectable()
export class StringInterceptor implements HttpInterceptor{
  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    if (typeof request.body === 'string') {     
        const contentType = request.headers.get('Content-Type')
        if (contentType == 'application/json' || contentType == 'text/json') {
            request = request.clone({
                body: JSON.stringify(request.body)
            });
        }
    }

    return next.handle(request)
  }
}

您还需要通过在提供程序注册中添加以下代码app.module.ts(确保导入您的拦截器)来注册拦截器:

    {
      provide: HTTP_INTERCEPTORS,
      useClass: StringInterceptor,
      multi: true
    },

还要确保删除自己的JSON.stringify(...)调用以避免所有字符串都有过多的引号。


推荐阅读