【问题标题】:The easiest way to proxy HttpServletRequest in Spring MVC controller在 Spring MVC 控制器中代理 HttpServletRequest 的最简单方法
【发布时间】:2017-05-17 10:21:36
【问题描述】:

我正在使用 spring-mvc 构建 REST 服务,我现在正在寻找一种从 Spring MVC 控制器内部将 HTTP 请求代理到外部 REST 服务的方法。

我正在获取 HttpServletRequest 对象并希望对其进行代理,从而尽可能少地进行更改。对我来说最重要的是保持传入请求的所有标头和属性不变。

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

我只是尝试使用 RestTemplate 向外部资源发送另一个 HTTP 请求,但我找不到复制 REQUEST ATTRIBUTES 的方法(这对我来说非常重要)。

提前致谢!

【问题讨论】:

  • 我也编写了一个代理(没有 REST)。我必须创建一个新的 HTTP 请求并将其发送到“外部”服务。我用Apache HTTP Components。这并不难,但需要两三行以上的代码来复制 HTTP 请求头并创建请求。
  • 您是否也尝试过复制属性?
  • 我必须复制请求参数(HTTP GET 的查询字符串或 HTTP POST 的消息正文)和请求标头。

标签: java spring http spring-mvc


【解决方案1】:

如果您考虑将 API 网关模式应用于微服务, 看看 Netflix zuul,它是 Spring Boot 生态系统中一个不错的选择。 here 提供了一个很好的例子。

【讨论】:

    【解决方案2】:

    您可以使用spring rest模板方法exchange将请求代理到第三方服务。

    @RequestMapping("/proxy")
    @ResponseBody
    public String proxy(@RequestBody String body, HttpMethod method, HttpServletRequest request, HttpServletResponse response) throws URISyntaxException {
        URI thirdPartyApi = new URI("http", null, "http://example.co", 8081, request.getRequestURI(), request.getQueryString(), null);
    
        ResponseEntity<String> resp =
            restTemplate.exchange(thirdPartyApi, method, new HttpEntity<String>(body), String.class);
    
        return resp.getBody();
    }
    

    What is the restTemplate.exchange() method for?

    【讨论】:

    • 本提案中根本不传递原始请求标头。并且响应标头也不会传递给客户端。这根本不是代理。
    • 在对象 HttpEntity 中,您可以使用对象 HttpHeaders 设置请求的原始标头。对象 ResponseEntity 包含响应的标头,它可以传递给客户端。
    • 这如何适用于多部分表单数据?对于多部分请求,@RequestBody 为空。
    • restTemplate 在你的代码中是在哪里定义的?你不需要添加 RestTemplate restTemplate = new RestTemplate();
    【解决方案3】:

    我在 Kotlin 中编写了这个 ProxyController 方法,用于将所有传入请求转发到远程服务(由主机和端口定义),如下所示:

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

    注意远程服务的API应该和这个服务完全一样。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-01-13
      • 1970-01-01
      • 2018-06-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多