为什么 request.ts 中的 serializeBody 方法不转换 JSON.stringify(this.body) 为大小写字符串?

Why serializeBody method in request.ts does not convert JSON.stringify(this.body) in case string?

当我将 string 值传递给 post 方法时,该值未被转换 JSON。 所以我们无法在 Controller 中获取此值。

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

Link

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

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 的方法,我想知道正确的使用方法。 谢谢。

Angular版本为8.1.0。 Java 是 Java 8。 Spring 是 5.1 / Spring 启动 2.1

仅仅是因为它们是两个完全不同的东西。 Angular(或 httpclient)无法通过魔法知道端点究竟需要或期望什么作为输入。

作为开发人员,生成与服务器接口匹配的 http 请求完全取决于您。

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

实际问题出在Angular code:

/**
* 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 interceptor 检查内容类型,如果它设置为 application/jsontext/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(...) 调用,以避免所有字符串都有过多的引号。