You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular 7请求OAuth Token报401 Unauthorized问题排查与解决

Angular 7请求OAuth Token返回401 Unauthorized的解决方案

我之前在Angular 7项目里请求OAuth Token时也碰到过一模一样的401问题——Postman测试完全正常,但自己写的代码就是返回Unauthorized,折腾了好一会儿才找到问题根源。

问题重现

先看看我最开始写的代码:

signin() {
  let signinData = this.signinForm.value;
  this.encoded = btoa("my-trusted-client:secret");
  let header = new Headers();
  header.append('Authorization', 'Basic ' + this.encoded);
  header.append('Content-type', 'application/x-www-form-urlencoded; charset=utf-8');
  this.http.post(this.url + '/oauth/token?grant_type=password&username=' + signinData.username + '&password=' + signinData.password, { headers: header })
    .subscribe(data => {
      console.log(data);
    })
}

返回的错误信息是这样的:

{
  "error": "Unauthorized",
  "message": "Unauthorized",
  "path": "/barometre/oauth/token",
  "status": 401,
  "timestamp": "2019-04-19T12:35:47.699+0000"
}

问题根源

问题出在请求参数的传递方式上:虽然我设置了Content-type为application/x-www-form-urlencoded,但实际是把参数直接拼在了URL里,而且Post请求的body部分是空的(第二个参数错误地传了headers配置,不是请求体)。OAuth的Token接口通常要求参数通过表单形式放在请求体中,而不是URL查询参数,这就导致服务端无法正确解析参数,直接返回了401。

修复方案

我们需要把grant_type、username、password这些参数通过表单形式放在请求体里传递,具体步骤如下:

  1. 新增一个序列化函数,把普通对象转换成URLSearchParams格式:
serialize(obj: any): URLSearchParams {
  let params: URLSearchParams = new URLSearchParams();
  for (var key in obj) {
    if (obj.hasOwnProperty(key)) {
      var element = obj[key];
      params.set(key, element);
    }
  }
  return params;
};
  1. 重构signin方法,正确传递请求体参数:
signin() {
  let signinData = this.signinForm.value;
  this.encoded = btoa("my-trusted-client:secret");
  let header = new Headers();
  header.append('Authorization', 'Basic ' + this.encoded);
  header.append('Content-type', 'application/x-www-form-urlencoded; charset=utf-8');

  // 构造请求参数对象
  let data = {
    grant_type: 'password',
    username: signinData.username,
    password: signinData.password
  };
  let params: URLSearchParams = this.serialize(data);

  // 正确传递请求体参数
  this.http.post(this.url + '/oauth/token', params, { headers: header })
    .subscribe(data => {
      console.log(data);
    })
}

为什么这样能解决问题?

现在参数是通过URLSearchParams序列化后放在Post请求的body里,完全符合application/x-www-form-urlencoded的格式要求,服务端能正确解析到grant_type、用户名和密码。而Postman之所以能成功,就是因为它默认会把表单参数正确放在请求体中,和我们修改后的请求格式完全一致。

内容的提问来源于stack exchange,提问作者Ragnar Lodbrok

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 05:19:29