Spring MVC - Calling a rest service from inside an

2020-05-28 21:00发布

问题:

I'm currently having a really weird issue with calling one REST service from inside another one and I could really use a hand in working out what I'm doing wrong.

So first off, a bit of context:

I have a webapp which calls off to a REST service to create a user account (for the sake of this explanation, the endpoint is localhost:8080/register). Earlier in the user journey I've called a different service to create the user's login credentials localhost:8090/signup but I need to check a few things in the call to /register so inside the call I'm calling out to a different endpoint on 8090 to get this information (localhost:8090/availability). Long story short, the webapp calls localhost:8080/register which in turn calls localhost:8090/availability.

When I call the availability endpoint directly, from either a REST client or the webapp itself, everything works as expected, but for some strange reason, when I call it from inside the call to the register endpoint I get a HTTP415. Anyone have any insight into what's going wrong?

The register controller looks like this:

@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;
}

And the availability controller looks like this:

@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;
}

Full disclosure - in practice, what I've shown as the contents of createUser() are actually several calls up the call stack, using the same class as I use to call the services from the webapp (which works perfectly well in that context), and I'm not actually just returning true in isUsernameAvailable (because that would be silly) but this is the simplest version of the code that replicates the issue.

My current assumption is that I'm doing something that I'm going to kick myself over when I see it but I've been staring at this code too long to be able to see it any more.

Edit Vikdor's comment below solved this problem for me. I changed the createUser method to:

@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;
}

回答1:

A HTTP415 means Unsupported Media Type. What that means is that isUsernameAvailable expects input in JSON format, but that isn't what it is getting.

Try explicitly adding Content-Type: application/json header to your HTTP request by doing the following:

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);

HttpEntity<String> entity = new HttpEntity<String>(requestJson,headers);
restTemplate.put(uRL, entity);


回答2:

Use RestTemplate.exchange mentioned below :

ResponseEntity responseEntity=RestTemplate.exchange(endPointURL, HttpMethod.GET/POST/PUT/DELETE, HttpEntity/headers, uriVariables)

endpointURL -- SOAP End point URL ,that the REST service has to consume.

HTTPMethod -- Method Type such as GET ,PUT ,POST ,DELETE etc.

HTTPEntity -- Soap requires for mandatory sender/headers/{a}.Make sure that you set your header name and value as key-Valye pair in HTTP headers.

uriVariables -- (Object... urivariables) such as String.class ,Integer.class

You should also put the connectTimeout ,isSSLDisabled,responseCached in the constructor while generating request to restTemplate.