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

您还应该将 connectTimeoutisSSLDisabledresponseCached 放在构造函数中,同时生成对 restTemplate 的请求。

【讨论】:

以上是关于Spring MVC - 从另一个休息服务内部调用休息服务的主要内容,如果未能解决你的问题,请参考以下文章

在spring boot微服务中,休息调用的调度不工作。

Spring RestTemplate 配置策略从单个 API 调用多个休息服务

使用 Spring Boot 从另一个服务调用 Rest Service 以进行课程注册系统

角后端服务调用没有休息调用

spring mvc 休息响应 json 和 xml

Spring Boot 休息服务 |不支持请求方法“GET”