我已经使用Spring MVC框架构建了一个Web应用程序来发布REST服务。例如:
@Controller
@RequestMapping("/movie")
public class MovieController {
@RequestMapping(value = "/{id}", method = RequestMethod.GET)
public @ResponseBody Movie getMovie(@PathVariable String id, @RequestBody user) {
return dataProvider.getMovieById(user,id);
}
现在我需要部署我的应用程序,但我有以下问题:客户端无法直接访问应用程序所在的计算机(有防火墙),因此我需要在代理计算机(可由客户端访问)上设置一个重定向层,以调用实际的rest服务。
我尝试使用RestTemplate进行新呼叫:例如:
@Controller
@RequestMapping("/movieProxy")
public class MovieProxyController {
private String address= "http://xxx.xxx.xxx.xxx:xx/MyApp";
@RequestMapping(value = "/{id}", method = RequestMethod.GET)
public @ResponseBody Movie getMovie(@PathVariable String id,@RequestBody user,final HttpServletResponse response,final HttpServletRequest request) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
RestTemplate restTemplate = new RestTemplate();
return restTemplate.exchange( address+ request.getPathInfo(), request.getMethod(), new HttpEntity<T>(user, headers), Movie.class);
}
这是可以的,但是我需要重写控制器中的每个方法来使用resttemplate。而且,这会导致代理机器上冗余的序列化/反序列化。
我试着用restemplate编写一个泛型函数,但没有成功:
@Controller
@RequestMapping("/movieProxy")
public class MovieProxyController {
private String address= "http://xxx.xxx.xxx.xxx:xx/MyApp";
@RequestMapping(value = "/**")
public ? redirect(final HttpServletResponse response,final HttpServletRequest request) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
RestTemplate restTemplate = new RestTemplate();
return restTemplate.exchange( address+ request.getPathInfo(), request.getMethod(), ? , ?);
}
我找不到一个resttemplate的方法,它可以处理请求和响应对象。
我也尝试了spring的重定向和转发,但是重定向并不改变请求的客户端IP地址,所以我认为在这种情况下它是无用的,我也不能转发到另一个URL。
有没有更适当的方法来达到这个目的?
8条答案
按热度按时间1bqhqjot1#
您可以使用以下命令镜像/代理所有请求:
这不会镜像任何标头。
0g0grzrc2#
以下是我对原始答案的修改版本,有四点不同:
1.它没有强制要求请求主体,因此不会让GET请求失败。
1.它会复制原始请求中的所有标头。如果您使用其他代理/Web服务器,这可能会导致内容长度/gzip压缩的问题。请将标头限制为您真正需要的标头。
1.它不会重新编码查询参数或路径。我们希望它们无论如何都被编码。请注意,URL的其他部分也可能被编码。如果您是这种情况,请充分利用
UriComponentsBuilder
的潜力。1.它确实从服务器正确返回错误代码。
beq87vna3#
您可以使用Netflix Zuul将来自一个Spring应用程序的请求路由到另一个Spring应用程序。
假设您有两个应用程序:1.歌曲应用程序,2. API网关
在api-gateway应用程序中,首先添加zuul dependecy,然后您可以在application.yml中简单地定义路由规则,如下所示:
pom.xml
application.yml
并且最后运行API网关应用,如:
现在,网关将把所有
/api/songs/
请求路由到http://localhost:8081/songs/
。下面是一个工作示例:https://github.com/muatik/spring-playground/tree/master/spring-api-gateway
其他资源:http://www.baeldung.com/spring-rest-with-zuul-proxy
8ehkhllq4#
@derkoe贴出了一个很棒的答案,对我帮助很大!
在2021年尝试了这个,我能够在这个基础上做一点改进:
1.如果类是@RestController,则不需要@ResponseBody
1.@RequestBody(required = false)允许不带正文的请求(例如GET)
1.如果您返回整个responseEntity而不是仅返回主体,那么您还将获得头部和响应代码。
1.添加(可选)标头的示例,例如
headers.put("Authorization", Arrays.asList(String[] { "Bearer 234asdf234"})
1.异常处理(捕获并转发HttpStatuses,如404,而不是抛出500服务器错误)
qvtsj1bj5#
具有oauth2的代理控制器
dwbf0jvd6#
如果您可以使用mod_proxy这样的低级解决方案,那么这将是更简单的方法,但如果您需要更多的控制(例如安全性、翻译、业务逻辑),您可能需要看看Apache Camel:http://camel.apache.org/how-to-use-camel-as-a-http-proxy-between-a-client-and-server.html
gpnt7bae7#
Veluria的解决方案给了我灵感,但我在从目标资源发送gzip压缩时遇到了问题。
目标是省略
Accept-Encoding
标头:ovfsdjhp8#
您需要类似
jetty transparent proxy
的代码,它实际上会重定向您的调用,并且如果需要,您可以覆盖请求。