【问题标题】:Angular HttpClient Get method with body带有正文的Angular HttpClient Get方法
【发布时间】:2019-01-12 21:45:02
【问题描述】:

我正在改进现有的 API,要求提供一个可以接受多个搜索条件并根据这些条件执行查询的单一 get 方法。

我正在使用 Spring MVC。 get 方法签名:

@GetMapping("/subscribers")
public ResponseEntity<List<SubscriberDTO>> getAllSubscribers(Pageable pageable, @RequestBody List<SearchCriteria> lstSearchCriteria)

该实现在 Postman 上按预期工作

现在我要去 Angular 实现前端,但我找不到通过 HttpClient Get 方法发送正文的方法...

我有点卡住了。我应该通过标题发送搜索条件吗?还是有更好的方法?

【问题讨论】:

标签: angular angular-httpclient


【解决方案1】:

据我所知,您不能使用 HttpClient get 发送正文。您至少可以使用该查询,因为它是惯用的。 (或者您可以尝试以某种方式强制解决问题)。

假设您有一个符合您的条件的数组:

const criteria = [ {a: 25}, {b: 23} ];
http.get(url + '/?criteria='+ encodeURIComponent( JSON.stringify(criteria)));

在 GET 请求中发送正文违反了某些 RFC 标准,即使它可能有效,您也一定会召唤一些神秘的恶魔。

【讨论】:

  • 您介意添加对您的声明“违反某些 RFC 标准”的引用以支持它吗?
  • RFC2616 第 4.3 节和第 5.1.1 节 - 虽然实际上它非常模糊,并建议 Web 服务器根据请求方法在不允许时丢弃正文 - 我知道大多数 Web 服务器确实丢弃了 BODY GET 请求上的行。事实上,甚至还有一些 Apache 的模组可以逆转这种行为。
  • 已被移除
  • RFC7231 第 4.3.1 节暗示允许 GET 请求中的主体但未明确定义。
【解决方案2】:

在服务方法中,您可以使用如下方法,该方法采用搜索查询的可选参数。您可以通过 Observe 发送您的搜索参数,如下所示。

getAllSubscribers(
    page?,
    itemsPerPage?,
    userParams?
  ): Observable<PaginatedResult<Subscribers[]>> {
    const paginatedResult: PaginatedResultSubscribers[]> = new PaginatedResult<
      Subscribers[]
    >();

    let params = new HttpParams();

    if (page != null && itemsPerPage != null) {
      params = params.append("pageNumber", page);
      params = params.append("pageSize", itemsPerPage);
    }

    if (userParams != null) {
      params = params.append("minAge", userParams.minAge);
      params = params.append("maxAge", userParams.maxAge);
        }

       return this.http
      .get<Subscribers[]>(this.baseUrl + "/subscribers", { observe: "response", params })
      .pipe(
        map(response => {
          paginatedResult.result = response.body;
          if (response.headers.get("Pagination") != null) {
            paginatedResult.pagination = JSON.parse(
              response.headers.get("Pagination")
            );
          }
          return paginatedResult;
        })
      );
  }

基本思想是使用HttpParams。

【讨论】:

  • 请记住,HttpParams不可变的。我花了一段时间弄清楚为什么 params.append() 不起作用。
  • @Odys - 好点。你可以做 new HttpParams().set(minAge", userParams.minAge).set("maxAge", userParams.maxAge)
【解决方案3】:

这里只是为了澄清一些答案,首先,如前所述,Angular 不支持为主体提供 GET 请求,并且没有办法解决这个问题。原因不是 Angular 的错,而是 XMLHttpRequest (XHR) 的错,浏览器用来发出请求的 API。 XHR 不支持带有 GET 请求的正文。

当前的 HTTP 标准中没有任何内容说带有 GET 请求的 Body 是无效的,只是它在语义上没有很好地定义。

在我看来,就 REST 而言,向主体提供 GET 请求比使用 POST 更可取。所以 XHR 不支持这个有点烦人。

【讨论】:

    【解决方案4】:

    为了让 Amir 的回答更通用,我做了以下操作来为传递的项目构建参数。

    在我的通用数据服务中,我添加了这个变体:

    // Get data for passed parameters or item containing filters
    public getByItem<T>(apiMethod: string, item?: T, apiParms?: HttpParams): Observable<T> {
        if (!apiParms) apiParms = new HttpParams();
        if (item) {
            const keys = Object.keys(item) as Array<keyof T>;
            for (let key of keys) {
                apiParms = apiParms.append(key.toString(), item[key].toString());
            }
        }
        // Call generic method of data service
        return this.get<T>(apiMethod, apiParms); // => return this.http.get<T>(environment.apiUrl + apiMethod, { headers: this.defaultHeaders
    

    【讨论】:

      【解决方案5】:

      get 请求是否可以有正文一直存在争议。我认为这不是这个线程的主题。如果您确实需要使用正文发出 get 请求(例如服务器强制要求),您可以使用 request 方法:

      request(method: string, url: string, options: {
              body?: any;
              headers?: HttpHeaders | {
                  [header: string]: string | string[];
              };
             //.......
              
          }): Observable<ArrayBuffer>;
      

      【讨论】:

        【解决方案6】:

        This 为我工作:

        import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http'; 
        
        filterBooks(category: string, year: string): Observable<Book[]> {
           let httpHeaders = new HttpHeaders()
                                 .set('Accept', 'application/json');
           let httpParams = new HttpParams()
                                .set('category', category)
                            .set('year', year);
           console.log(httpParams.toString());
           console.log(httpHeaders.keys());
           return this.http.get<Book[]>(this.bookUrl, {
                        headers: httpHeaders,
                        params: httpParams, 
                        responseType: 'json'
                });
        } 
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-09-14
          • 2023-03-29
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-03-05
          相关资源
          最近更新 更多