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

Spring RestTemplate调用返回401未授权错误排查求助

问题排查:adminappPreProd调用appPreProd出现401未授权错误

背景信息

需要通过HTTP实现adminappPreProd服务调用appPreProd服务,两个服务的容器端口信息如下:

c053b74b7e3a   app-pre_prod:latest      "java -jar -Dspring.…"   0.0.0.0:8080->8080/tcp, :::8080->8080/tcp                                  appPreProd
77d20ec0905c   adminapp-pre_prod:latest      "java -jar -Dspring.…"   0.0.0.0:8980->9080/tcp, :::9080->9080/tcp                                  adminappPreProd

调用代码如下:

String tenantId = Long.toString(productUserMO.getId());

HttpHeaders headers = new HttpHeaders();
headers.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
map.add(Constants.X_TENANTID, tenantId);
HttpEntity<?> entity = new HttpEntity<Object>(map, headers);
restTemplate().exchange(apiURI.concat("/addPackageTypesForProductOwner"), HttpMethod.GET, entity,
        String.class);

调用时出现错误:

org.springframework.web.client.HttpClientErrorException$Unauthorized:
401 : "Unauthorized access"

已知情况:

  • 服务未启用HTTPS
  • 目标API已豁免授权校验,但请求并未到达appPreProd服务
  • 调整请求头后问题仍未解决

排查及解决方案

1. 修复GET请求携带请求体的不规范写法

HTTP规范中GET请求不应该携带请求体,虽然部分客户端支持,但Spring MVC等服务端框架会直接拦截这类请求,导致请求无法到达业务代码,触发401错误。

两种修复方式:

  • 方式一:将tenantId放到URL参数中
String tenantId = Long.toString(productUserMO.getId());
HttpHeaders headers = new HttpHeaders();
headers.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
HttpEntity<?> entity = new HttpEntity<>(headers);
// 拼接tenantId到URL参数
String targetUrl = apiURI.concat("/addPackageTypesForProductOwner")
        .concat("?").concat(Constants.X_TENANTID).concat("=").concat(tenantId);
restTemplate().exchange(targetUrl, HttpMethod.GET, entity, String.class);
  • 方式二:将tenantId放到请求头中
    如果业务要求必须通过请求头传递tenantId,直接把它加入HttpHeaders即可,无需使用请求体:
String tenantId = Long.toString(productUserMO.getId());
HttpHeaders headers = new HttpHeaders();
headers.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
headers.set(Constants.X_TENANTID, tenantId); // 直接添加到请求头
HttpEntity<?> entity = new HttpEntity<>(headers);
restTemplate().exchange(apiURI.concat("/addPackageTypesForProductOwner"), HttpMethod.GET, entity, String.class);

2. 检查RestTemplate的拦截器配置

如果你的restTemplate()方法配置了全局拦截器,比如自动添加授权token的拦截器,可能会导致请求被中间件或服务端拦截。

  • 排查restTemplate()的初始化代码,看是否添加了ClientHttpRequestInterceptor类型的拦截器
  • 如果存在不必要的授权拦截器,要么移除,要么针对该请求单独配置不带拦截器的RestTemplate实例

3. 确认API豁免授权的规则有效性

即使你配置了豁免,也要验证规则是否匹配:

  • 检查豁免的URL路径是否和请求的路径完全一致(注意大小写、是否包含额外路径)
  • 确认豁免规则是否包含GET请求方法,部分配置可能只豁免POST/PUT等方法
  • 查看appPreProd服务的访问日志,如果日志中完全没有该请求的记录,说明请求在网关、服务网格等中间件层就被拦截了,需要检查中间件的认证规则

4. 验证服务间网络及中间件配置

  • 先通过curl或postman从adminappPreProd容器内部测试访问appPreProd的8080端口,确认网络连通性
  • 如果部署在容器集群中,检查是否有服务网格(比如Istio)或网关强制要求服务间认证,即使目标API豁免,中间件仍可能要求服务携带合法的身份凭证

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 16:11:07