我建立使用Spring MVC框架发布REST服务的Web应用程序。 例如:
@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的方法与请求和响应对象的作品。
我也试着春天的重定向和转发。 但是,重定向,所以我认为这是在这种情况下无用不会改变请求的客户端IP地址。 我也不转发到另一个网址。
有没有更合适的方式来实现这一目标? 提前致谢。
可以镜像/代理这一切要求:
private String server = "localhost";
private int port = 8080;
@RequestMapping("/**")
@ResponseBody
public String mirrorRest(@RequestBody String body, HttpMethod method, HttpServletRequest request) throws URISyntaxException
{
URI uri = new URI("http", null, server, port, request.getRequestURI(), request.getQueryString(), null);
ResponseEntity<String> responseEntity =
restTemplate.exchange(uri, method, new HttpEntity<String>(body), String.class);
return responseEntity.getBody();
}
这不会反映任何头。
您可以使用Netflix的Zuul将请求路由来Spring应用程序到另一个Spring应用程序。
比方说,你有两个应用:1.songs-应用,2.api网关
在API网关的应用程序,先添加zuul dependecy,那么你可以简单地定义你的application.yml路由规则如下:
的pom.xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
<version>LATEST</version>
</dependency>
application.yml
server:
port: 8080
zuul:
routes:
foos:
path: /api/songs/**
url: http://localhost:8081/songs/
,最后运行API网关的应用,如:
@EnableZuulProxy
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
现在,网关将路由所有/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
这是我原来的答案,它不同于四点的修改后的版本:
- 它不会使请求体强制性的,因此不会让GET请求失败。
- 它的副本出现在原始请求的所有头。 如果你使用的是其他代理/ Web服务器,这可能会导致由于内容长度/ gzip压缩的问题。 限制头给你真正需要的人。
- 它不重新编码的查询参数或路径。 我们期待他们无论如何编码。 请注意,您的网址的其他部分也可能被编码。 如果这是你的情况下,利用的全部潜力
UriComponentsBuilder
。 - 它从服务器正确返回错误代码。
@RequestMapping("/**")
public ResponseEntity mirrorRest(@RequestBody(required = false) String body,
HttpMethod method, HttpServletRequest request, HttpServletResponse response)
throws URISyntaxException {
String requestUrl = request.getRequestURI();
URI uri = new URI("http", null, server, port, null, null, null);
uri = UriComponentsBuilder.fromUri(uri)
.path(requestUrl)
.query(request.getQueryString())
.build(true).toUri();
HttpHeaders headers = new HttpHeaders();
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
headers.set(headerName, request.getHeader(headerName));
}
HttpEntity<String> httpEntity = new HttpEntity<>(body, headers);
RestTemplate restTemplate = new RestTemplate();
try {
return restTemplate.exchange(uri, method, httpEntity, String.class);
} catch(HttpStatusCodeException e) {
return ResponseEntity.status(e.getRawStatusCode())
.headers(e.getResponseHeaders())
.body(e.getResponseBodyAsString());
}
}
如果你能逃脱使用像mod_proxy的较低级别的解决方案,将是一段简单的方式,但如果你需要更多的控制(例如安全,翻译,业务逻辑),你可能想看看Apache的骆驼: HTTP ://camel.apache.org/how-to-use-camel-as-a-http-proxy-between-a-client-and-server.html
代理控制器的oauth2
@RequestMapping("v9")
@RestController
@EnableConfigurationProperties
public class ProxyRestController {
Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
OAuth2ProtectedResourceDetails oAuth2ProtectedResourceDetails;
@Autowired
private ClientCredentialsResourceDetails clientCredentialsResourceDetails;
@Autowired
OAuth2RestTemplate oAuth2RestTemplate;
@Value("${gateway.url:http://gateway/}")
String gatewayUrl;
@RequestMapping(value = "/proxy/**")
public String proxy(@RequestBody(required = false) String body, HttpMethod method, HttpServletRequest request, HttpServletResponse response,
@RequestHeader HttpHeaders headers) throws ServletException, IOException, URISyntaxException {
body = body == null ? "" : body;
String path = request.getRequestURI();
String query = request.getQueryString();
path = path.replaceAll(".*/v9/proxy", "");
StringBuffer urlBuilder = new StringBuffer(gatewayUrl);
if (path != null) {
urlBuilder.append(path);
}
if (query != null) {
urlBuilder.append('?');
urlBuilder.append(query);
}
URI url = new URI(urlBuilder.toString());
if (logger.isInfoEnabled()) {
logger.info("url: {} ", url);
logger.info("method: {} ", method);
logger.info("body: {} ", body);
logger.info("headers: {} ", headers);
}
ResponseEntity<String> responseEntity
= oAuth2RestTemplate.exchange(url, method, new HttpEntity<String>(body, headers), String.class);
return responseEntity.getBody();
}
@Bean
@ConfigurationProperties("security.oauth2.client")
@ConditionalOnMissingBean(ClientCredentialsResourceDetails.class)
public ClientCredentialsResourceDetails clientCredentialsResourceDetails() {
return new ClientCredentialsResourceDetails();
}
@Bean
@ConditionalOnMissingBean
public OAuth2RestTemplate oAuth2RestTemplate() {
return new OAuth2RestTemplate(clientCredentialsResourceDetails);
}
你需要像jetty transparent proxy
,这实际上会重定向你的电话,你会得到一个机会,如果你需要覆盖的要求。 你可以在获得其详细http://reanimatter.com/2016/01/25/embedded-jetty-as-http-proxy/