Feign调用返回404 Not Found但链接可正常访问的问题排查
Feign调用Azure设备码接口返回404的原因及解决方法
问题原因
你的代码存在两个核心问题,导致请求不符合Azure设备码接口的要求:
- 请求体格式不匹配:方法上使用
@RequestBody注解后,Feign会将Request对象序列化为JSON格式发送,但接口要求的是application/x-www-form-urlencoded的表单格式,Azure服务器无法正确解析该请求,进而返回404错误。 - 参数注解无效:
Requestrecord字段上的@RequestParam注解不会被Feign识别——该注解仅作用于方法参数层面,因此实际请求中并未携带client_id和scope参数,接口因缺少必要参数判定请求无效。
解决方法
以下三种方案均可解决问题,任选其一即可:
方案一:直接使用@RequestParam作为方法参数
将参数直接定义在方法上,Feign会自动将其拼接为表单格式:
@FeignClient(name = "device-code", url = AzureTokenClient.BASE_URL) public interface AzureTokenClient { String SCOPE = URLEncoder.encode("offline_access files.read.all", Charsets.UTF_8); String BASE_URL = "https://login.microsoftonline.com"; @PostMapping(value = "/common/oauth2/v2.0/devicecode", consumes = "application/x-www-form-urlencoded") Map<String, Object> getDeviceCode(@RequestParam("client_id") String clientId, @RequestParam("scope") String scope); }
方案二:使用@ModelAttribute封装参数
保留Request record,去掉字段上的@RequestParam,方法参数使用@ModelAttribute注解,Feign会自动将record字段转为表单参数:
@FeignClient(name = "device-code", url = AzureTokenClient.BASE_URL) public interface AzureTokenClient { String SCOPE = URLEncoder.encode("offline_access files.read.all", Charsets.UTF_8); String BASE_URL = "https://login.microsoftonline.com"; @PostMapping(value = "/common/oauth2/v2.0/devicecode", consumes = "application/x-www-form-urlencoded") Map<String, Object> getDeviceCode(@ModelAttribute Request dto); } record Request(String clientId, String scope) implements Serializable { }
方案三:使用MultiValueMap作为请求体
直接构建表单格式的请求体,适合参数较多或动态参数的场景:
@FeignClient(name = "device-code", url = AzureTokenClient.BASE_URL) public interface AzureTokenClient { String SCOPE = URLEncoder.encode("offline_access files.read.all", Charsets.UTF_8); String BASE_URL = "https://login.microsoftonline.com"; @PostMapping(value = "/common/oauth2/v2.0/devicecode", consumes = "application/x-www-form-urlencoded") Map<String, Object> getDeviceCode(@RequestBody MultiValueMap<String, String> params); }
调用时构建参数:
MultiValueMap<String, String> params = new LinkedMultiValueMap<>(); params.add("client_id", "你的客户端ID"); params.add("scope", AzureTokenClient.SCOPE); azureTokenClient.getDeviceCode(params);
内容的提问来源于stack exchange,提问作者Madray Haven
相关产品推荐
相关产品推荐

