7

I'm building REST services using spring-mvc and what I'm looking for now is a way to proxy HTTP request to external REST service from inside Spring MVC controller.

I'm getting HttpServletRequest object and want to proxy it making as few changes as possible. What is essential for me is keeping all the headers and attributes of incoming request as they are.

@RequestMapping('/gateway/**')
def proxy(HttpServletRequest httpRequest) {
    ...
}

I was trying simply to send another HTTP request to external resource using RestTemplate but I failed to find a way to copy REQUEST ATTRIBUTES (which is very important in my case).

Thanks in advance!

Ghosty
  • 83
  • 1
  • 1
  • 5
  • I've programmed a proxy too (without REST). I had to create a new HTTP request and sent it to the "external" service. I used [Apache HTTP Components](http://hc.apache.org/). That's not difficult, but it needs more than two or three lines of code to copy the HTTP request headers and create the request. – JimHawkins Jan 03 '17 at 10:57
  • Have you tried to copy attributes as well? – Ghosty Jan 03 '17 at 11:01
  • I had to copy the request parameters (query string for HTTP GET or message body for HTTP POST) and the request headers. – JimHawkins Jan 03 '17 at 11:03

3 Answers3

5

I wrote this ProxyController method in Kotlin to forward all incoming requests to remote service (defined by host and port) as follows:

@RequestMapping("/**")
fun proxy(requestEntity: RequestEntity<Any>, @RequestParam params: HashMap<String, String>): ResponseEntity<Any> {
    val remoteService = URI.create("http://remote.service")
    val uri = requestEntity.url.run {
        URI(scheme, userInfo, remoteService.host, remoteService.port, path, query, fragment)
    }

    val forward = RequestEntity(
        requestEntity.body, requestEntity.headers,
        requestEntity.method, uri
    )

    return restTemplate.exchange(forward)
}

Note that the API of the remote service should be exactly same as this service.

Martin Kalina
  • 111
  • 1
  • 7
3

You can use the spring rest template method exchange to proxy the request to a third party service.

@RequestMapping("/proxy")
@ResponseBody
public String proxy(@RequestBody String body, HttpMethod method, HttpServletRequest request) throws URISyntaxException {
    URI thirdPartyApi = new URI("http", null, "http://example.co", 8081, request.getRequestURI(), request.getQueryString(), null);

    RestTemplate restTemplate = new RestTemplate();
    ResponseEntity<String> resp =
        restTemplate.exchange(thirdPartyApi, method, new HttpEntity<String>(body), String.class);

    return resp.getBody();
}

What is the restTemplate.exchange() method for?

matth
  • 6,112
  • 4
  • 37
  • 43
db80
  • 4,157
  • 1
  • 38
  • 38
  • 3
    Original request headers are not passed at all in this proposal. And response headers are not passed to the client as well. This is not a proxy at all. – Krzysztof Tomaszewski Nov 27 '18 at 09:56
  • In the object HttpEntity you can set the original headers of the request using the object HttpHeaders. The object ResponseEntity contains the headers of the response and it can be passed to the client. – db80 Dec 16 '18 at 20:54
  • 1
    How can this work for multipart form data? @RequestBody is empty for multipart request. – Richard Domingo Jan 28 '19 at 14:33
  • 1
    Where did restTemplate get defined in your code? Wouldn't you need to add RestTemplate restTemplate = new RestTemplate(); – ledlogic Jul 12 '20 at 22:11
0

if you think of applying the API gateway pattern for microservices, have a look at Netflix zuul which is a good alternative in the spring boot ecosystem. A good example is provided here.

Guy Bouallet
  • 2,099
  • 11
  • 16