Spring MVC - 从另一个休息服务内部调用休息服务
Posted
技术标签:
【中文标题】Spring MVC - 从另一个休息服务内部调用休息服务【英文标题】:Spring MVC - Calling a rest service from inside another rest service 【发布时间】:2016-04-02 21:28:18 【问题描述】:我目前在从另一个服务内部调用一个 REST 服务时遇到了一个非常奇怪的问题,我真的可以用一只手来找出我做错了什么。
首先,先来点上下文:
我有一个 webapp,它调用 REST 服务来创建用户帐户(为了便于说明,端点是 localhost:8080/register)。在用户旅程的早期,我调用了一个不同的服务来创建用户的登录凭据localhost:8090/signup
,但我需要在调用 /register 时检查一些事情,所以在调用中我调用了 8090 上的不同端点获取此信息 (localhost:8090/availability
)。长话短说,webapp 调用了 localhost:8080/register,而后者又调用了localhost:8090/availability
。
当我从 REST 客户端或 web 应用程序本身直接调用可用性端点时,一切都按预期工作,但由于某种奇怪的原因,当我从调用内部对注册端点调用它时,我得到一个 HTTP415。任何人都知道出了什么问题?
寄存器控制器如下所示:
@RequestMapping(method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseStatus(HttpStatus.OK)
public UserModel createUser(@RequestBody UserModel userModel) throws InvalidSignupException
// a load of business logic that validates the user model
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<Boolean> response = restTemplate.postForEntity("http://localhost:8090/availability",
userModel.getUsername(), Boolean.class);
System.out.println(response.getBody());
// a load more business logic
return userModel;
可用性控制器如下所示:
@RequestMapping(method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseStatus(HttpStatus.OK)
public Boolean isUsernameAvailable(@RequestBody String username)
// a load of business logic that returns a boolean
return Boolean.TRUE;
完全公开 - 实际上,我所展示的 createUser() 内容实际上是调用堆栈中的几个调用,使用与从 webapp 调用服务相同的类(在那个上下文),我实际上并不仅仅是在 isUsernameAvailable 中返回 true (因为那会很愚蠢),但这是复制问题的最简单的代码版本。
我目前的假设是,我正在做一些当我看到它时我会踢自己的事情,但我已经盯着这段代码太久了,无法再看到它了。
编辑 Vikdor 下面的评论为我解决了这个问题。我将 createUser 方法更改为:
@RequestMapping(method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseStatus(HttpStatus.OK)
public UserModel createUser(@RequestBody UserModel userModel) throws InvalidSignupException
// a load of business logic that validates the user model
RestTemplate restTemplate = new RestTemplate();
restTemplate.setMessageConverters(Arrays.asList(new MappingJackson2HttpMessageConverter()));
ResponseEntity<Boolean> response = restTemplate.postForEntity("http://localhost:8090/availability",
userModel.getUsername(), Boolean.class);
System.out.println(response.getBody());
// a load more business logic
return userModel;
【问题讨论】:
HTTP 状态码415
表示传递给 API 的媒体类型不正确。您似乎期待应用程序/json,但发送文本/纯文本(用户名)。你可能想将MappingJacksonHttpMessageConverter
设置为rest模板,看看调用是否成功。
POST request via RestTemplate in JSON的可能重复
您是否有理由为每个请求创建一个新模板而不是使其成为一个字段?
【参考方案1】:
HTTP415 表示不支持的媒体类型。这意味着isUsernameAvailable
需要 JSON 格式的输入,但这不是它所得到的。
尝试通过执行以下操作将Content-Type: application/json
标头显式添加到您的 HTTP 请求中:
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<String>(requestJson,headers);
restTemplate.put(uRL, entity);
【讨论】:
【参考方案2】:使用下面提到的 RestTemplate.exchange :
ResponseEntity<String> response = RestTemplate.exchange(EndPointURL, HttpMethod.GET/POST/PUT/DELETE, HttpEntity/headers, URI-Variables)
输入参数描述如下:
EndpointURL -- SOAP 端点 URL,REST 服务必须使用。
HTTPMethod -- 方法类型,例如 GET ,PUT ,POST ,DELETE 等。
HTTPEntity -- Soap 需要强制性的发件人标头。确保将标头名称和值设置为 HTTP 标头中的键值对。
URI-Variables -- (Object...urivariables) 例如 String.class ,Integer.class
您还应该将 connectTimeout 、 isSSLDisabled 、 responseCached 放在构造函数中,同时生成对 restTemplate 的请求。
【讨论】:
以上是关于Spring MVC - 从另一个休息服务内部调用休息服务的主要内容,如果未能解决你的问题,请参考以下文章
Spring RestTemplate 配置策略从单个 API 调用多个休息服务