【问题标题】:Angular 7 post request with body and header带有正文和标头的 Angular 7 发布请求
【发布时间】:2019-06-23 07:22:44
【问题描述】:

我正在尝试使用正文和标题进行发布请求。以下是我经历过的一些变体,但在大多数情况下,我在服务器上遇到错误,说参数“key”没有传入。

我在邮递员中尝试了这个 api,它在那里工作。这就是我在 Java/Spring Boot 中定义方法头的方式:

@RequestMapping(value = "/getIssue", method = RequestMethod.POST)
public IssuePojo getIssue(@RequestParam("key") String key, HttpServletRequest request) {

以下是我的角度变化:

public getJiraIssue(key: string): Observable<any> {

    let headers = new HttpHeaders({
      'Content-Type': 'application/json',
      'Authorization': this.idToken });
    let options = { headers: headers };

    const paramsA = new URLSearchParams();
    paramsA.set('key', key);
    let params = new HttpParams().append('key', key);
    // return this.http.post(this.urlEnvironment.jiraGetIssue(), params, this.getHeaders());
    console.log("headers: ", this.getHeaders());
    // let obj = {
    //   key: key
    // }

    var headersA = new Headers();
    headers.append('Authorization', this.idToken);

    let body = new HttpParams()
    .set('key', key);

    return this.http.post(this.urlEnvironment.jiraGetIssue(), body, {headers: headers});
    // return this.http.post(this.urlEnvironment.jiraGetIssue(), null, {headers: this.getHeaders(), params: params});
  }

似乎正在发送正文:

但这是我得到的错误:

timestamp: "2019-01-30T04:30:40.721+0000", status: 400, error: "Bad Request",…}
error: "Bad Request"
message: "Required String parameter 'key' is not present"
path: "/jira/getIssue"
status: 400
timestamp: "2019-01-30T04:30:40.721+0000"
trace: "org.springframework.web.bind.MissingServletRequestParameterException: Required String parameter 'key' is not present

【问题讨论】:

  • OK:这样您就可以成功地从 Postman 查询 Jira,所以您知道 a) HTTP 标头应该是什么('Content-Type': 'application/json' 和 'Authorization' :XYZ),并且您知道正文应该是什么(像这样的 JSON:developer.atlassian.com/server/jira/platform/…)。到目前为止,一切都很好。问:谁在查询 Jira:你的 JS/Angular 前端,还是你的 Java/Spring boot 后端?问:您是否查看过正在发送的 HTTP(Fiddler 或 Wireshark)?
  • 我是说我已经验证我的 Java API 正在通过 Postman 工作。 Java 正在查询 Jira
  • 问:您是否能够在任何地方成功查询 Jira?爪哇?邮差?卷曲?问:您是否确认了 HTTP 正文 应该 的外观?我怀疑它可能应该是 JSON(如 here),并且 NOT 是像“key=WJC-7”这样的字符串。建议:验证消息格式。
  • 是的,API 工作正常。我以不同的方式测试了我的方法,从 Java 和邮递员。如果我从方法中取出我的 Servlet,那么它就可以工作了。

标签: angular rest spring-boot


【解决方案1】:

HttpParams() 用于在需要时将查询字符串参数添加到请求 URL,然后首先检查是否将其添加到开发人员工具请求中,如果存在,则 api 端有问题

【讨论】:

  • 不,我不需要 URL 参数。我需要通过body的参数。
  • 如果我没有错,Java 中的@RequestParam 也意味着只从查询字符串中获取数据,如下链接建议reversecoding.net/…
  • 好的,那我做错了什么?为什么它会从邮递员那里工作?那我需要改变什么?
  • 如果你想把它传递给 body 然后试试下面的代码 let body = {'key', key};返回 this.http.post(this.urlEnvironment.jiraGetIssue(), body, {headers: headers});
  • 我不熟悉java,但正如你所说,这是与邮递员一起工作的,你能检查一下邮递员是如何发出请求的,如果它是在正文中发送的,然后尝试上面的方法,在java论坛中发布另一个问题解决这个问题
【解决方案2】:

使用这个HHTP服务类在body中发送参数,你也可以在headers中发送

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
import { Observable, empty } from 'rxjs';
import { catchError, timeout } from 'rxjs/operators';


@Injectable({
  providedIn: 'root'
})
export class HttpService {
  constructor(private http: HttpClient) {
  }

  private getHeaders(headersConfig?: object): HttpHeaders {
    return new HttpHeaders({
      'Content-Type': 'application/json',
      ...headersConfig,
    });
  }

  get(url: string, params: HttpParams = new HttpParams(), headers: Object): Observable<any> {
    let finalHeaders = this.getHeaders();
    if (headers) {
      for (let key in headers) {
        finalHeaders = finalHeaders.append(key, headers[key]);
      }
    }
    return this.http.get(
      url,
      { headers: finalHeaders, params }
    ).pipe(timeout(10000)).pipe(catchError(this.handleError('Get request')));
  }

  put(url: string, body: Object = {}, headers: Object): Observable<any> {
    let finalHeaders = this.getHeaders();
    if (headers) {
      for (let key in headers) {
        finalHeaders = finalHeaders.append(key, headers[key]);
      }
    }
    return this.http.put(
      url,
      body,
      { headers: finalHeaders }
    ).pipe(timeout(10000)).pipe(catchError(this.handleError<any>('put request')));
  }

  post(url: string, body: Object = {}, headers: Object): Observable<any> {
    let finalHeaders = this.getHeaders();
    if (headers) {
      for (let key in headers) {
        finalHeaders = finalHeaders.append(key, headers[key]);
      }
    }
    return this.http.post(
      url,
      body,
      { headers: finalHeaders }
    ).pipe(timeout(10000)).pipe(catchError(this.handleError<any>('post request')));
  }

  /**
 * Handle Http operation that failed.
 * Let the app continue.
 * @param operation - name of the operation that failed
 * @param result - optional value to return as the observable result
 */
  private handleError<T>(operation = 'operation', result?: T) {
    return (error: any): Observable<T> => {
      return empty();//of(result as T);
    };
  }
}

【讨论】:

  • 我不想将我的参数与我的标题结合起来。我想把两者分开
  • 如果你将 header 传递为 null,post 方法将不会在请求中添加 header。
  • 但是我需要同时发送标题和正文
  • this.httpService.put(yourURL, bodyData, headerData)。您可以通过设置 headerData = null 来仅发送 bodyParam。
  • 如果bodyData和headerData都不为null,则都发送。
【解决方案3】:

所以关键是'Content-Type': 'application/json', 因为我正在发送json,所以在服务器端它期望将它映射到一个对象。我设法让它与字符串一起工作,但是我必须自己在服务器上解析字符串,这不是我想要做的。

所以'Content-Type': 'text/plain', => 映射到 => @RequestBody String key

'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', => 映射到 => @RequestParam String key, @RequestParam String test,

因此来自 Angular 的 post 调用将如下所示:

const httpBody = new HttpParams()
      .set('key', 'key')
      .set('test', 'test');
    return this.http.post(endPoint, httpBody, this.getArgHeaders());

  private getArgHeaders(): any {
      const httpOptions = {
        headers: new HttpHeaders({
          'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
        })
      };
      return httpOptions;
  }

【讨论】:

    【解决方案4】:

    好的,我的理解是你有一个 JS/Angular 7 前端。它正在与 Java/Spring Boot 后端对话,后者反过来查询 Jira:

        Angular       SpringBoot         Jira
       --------- (1)  ----------- (2) ----------
       (service) --> (controller) --> (Jira API)
                 <--              <--
                 (4)              (3)
    

    到目前为止正确吗?

    听起来您可以使用 Postman 成功查询 Jira(请求 2,响应 3),对吗?

    问题是当 Angular 查询 Spring Boot(请求 1)时,你得到 HTTP 400: "Required String parameter 'key' is not present",对吗?

    这就是我在上面的 cmets 中试图问的问题。问题显然是您的消息有效负载“key=WJC-7”不是有效的 JSON。所以请求失败。

    根据您分享的内容,我在这里做了很多“假设”。尽管如此:

    建议:

    1. 让 Angular 创建对象:let obj = { key: key };,就像您一开始所做的那样。

    2. 确保它完整(我认为 Jira API 需要的不仅仅是“密钥”)。

    3. 确保您发送的 Angular 对象匹配 - field-for-field - Spring Boot 控制器期望的 Java 对象。 Spring Boot 应该在 JSON 中自动序列化/反序列化。

    4. 让 Angular 发送对象(作为“数据”)。您的“消息负载”!=“消息头”。

    5. Be SURE 检查每一步发送和接收的有效负载(上面的 1、2、3 和 4)。您可以使用 Fiddler、Wireshark 或跟踪日志来执行此操作。

    '希望有帮助!

    PS: 下面是一个 Angular 客户端可能调用的 Java Spring Boot 控制器的假设示例:

    ...
    @RestController
    @CrossOrigin(origins = "http://localhost:4200")
    public class TodoResource {
    
        @Autowired
        private TodoHardcodedService todoService;
    
        // GET All todos
        @GetMapping("/users/{username}/todos")
        public List<Todo> getAllTodos(@PathVariable String username) {
            return todoService.findAll();
        }
    ...
    

    这里是对应的Java“Todo”对象示例:

    public class Todo {
        private long id;
        private String username;
        private String description;
        private Date targetDate;
        private boolean isDone;
        ...
    

    【讨论】:

    • 是的,但是如果我只需要发送两个参数怎么办?只有3个,只有4个?也许在 4 个论点我可以开始用 Java 创建 Pojos。但是我不应该继续创建 Pojos 的 1、2 或 3 个参数。
    • 您最初的抱怨是“它不起作用”。我们现在知道为什么了。我希望以上内容有用。现在你有了new“需求”:你想要“变量参数”。这是一个“可以做的”。这也是一个单独的问题。你有不同的选择......但让我们一次处理一件事。 Quick'n'dirty,temp 解决方案:只需在 POJO 中声明 all 您的属性,并让控制器 ignore 客户端未发送的属性。
    • PS:您可能也有兴趣查看Lombok
    猜你喜欢
    • 1970-01-01
    • 2017-08-31
    • 2020-12-23
    • 2019-04-15
    • 2019-04-11
    • 2019-12-18
    • 2018-03-28
    • 2021-08-13
    • 2018-12-06
    相关资源
    最近更新 更多