J'ai construit une application Web à l'aide de Spring MVC Framework pour publier les services REST . Par exemple:
@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);
}
Maintenant, je dois déployer mon application, mais le problème est le suivant: Par conséquent, j'ai besoin d'une couche de redirection sur une machine proxy (accessible par les clients) qui appelle le service de repos réel.
J'ai essayé de faire un nouvel appel en utilisant RestTemplate: Par exemple:
@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);
}
C'est ok, mais je dois réécrire chaque méthode du contrôleur pour utiliser le reste du modèle. De plus, cela entraîne une sérialisation/désérialisation redondante sur la machine proxy.
J'ai essayé d'écrire une fonction générique en utilisant restemplate, mais cela n'a pas fonctionné:
@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(), ? , ?);
}
Je n'ai pas trouvé de méthode de resttemplate qui fonctionne avec les objets request et response.
J'ai aussi essayé de rediriger le printemps et de transmettre. Mais la redirection ne change pas l'adresse IP du client de la requête, je pense donc qu'elle est inutile dans ce cas. Je ne pouvais pas transférer à une autre URL non plus.
Existe-t-il un moyen plus approprié d’y parvenir? Merci d’avance.
Vous pouvez mettre en miroir/proxy toutes les demandes avec ceci:
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();
}
Cela ne reflétera aucun en-tête.
Vous pouvez utiliser Netflix Zuul pour acheminer les demandes arrivant d'une application de printemps vers une autre application de printemps.
Disons que vous avez deux applications: 1.songs-app, 2.api-gateway
Dans l'application api-gateway, ajoutez d'abord la dépendance zuul, puis vous pouvez simplement définir votre règle de routage dans application.yml comme suit:
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/
et enfin, lancez l'application api-gateway comme:
@EnableZuulProxy
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Maintenant, la passerelle routera toutes les requêtes /api/songs/
vers http://localhost:8081/songs/
.
Voici un exemple pratique: https://github.com/muatik/spring-playground/tree/master/spring-api-gateway
Une autre ressource: http://www.baeldung.com/spring-rest-with-zuul-proxy
Voici ma version modifiée de la réponse originale, qui diffère en quatre points:
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());
}
}
Si vous pouvez vous en tirer en utilisant une solution de niveau inférieur, telle que mod_proxy, ce serait la solution la plus simple, mais si vous avez besoin de plus de contrôle (par exemple sécurité, traduction, logique métier), vous voudrez peut-être jeter un coup d'œil à Apache Camel: http://camel.Apache.org/how-to-use-camel-as-a-http-proxy-between-a-client-and-server.html
contrôleur proxy avec 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);
}
Vous avez besoin de quelque chose comme jetty transparent proxy
, qui redirigera réellement votre appel, et vous aurez la possibilité d'écraser la demande si vous en aviez besoin. Vous pouvez obtenir ses détails à http://reanimatter.com/2016/01/25/embedded-jetty-as-http-proxy/