2013-02-06 15 views
34

Ich habe eine Web-Anwendung mit Feder Mvc-Framework zu veröffentlichen REST-Dienste. Zum Beispiel:Spring Mvc Rest Service Redirect/Forward/Proxy

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

} 
. 
. 
. 

Jetzt muss ich meine Anwendung bereitstellen, aber ich habe folgendes Problem: Die Clients, auf denen keinen direkten Zugriff auf den Computer haben die Anwendung befindet (Es gibt eine Firewall). Daher benötige ich einen Umleitungs-Layer auf einem Proxy-Rechner (auf den die Clients zugreifen können), der den eigentlichen Rest-Service aufruft.

Ich habe versucht, einen neuen Anruf RestTemplate mit: Beispiel:

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

} 
. 
. 
. 

Das ist in Ordnung, aber ich brauche jede Methode in der Steuerung neu zu schreiben, die resttemplate zu verwenden. Dies führt auch zu einer redundanten Serialisierung/Deserialisierung auf dem Proxy-Rechner.

Ich habe versucht, eine generische Funktion restemplate zu schreiben, aber es hat nicht geklappt:

@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(), ? , ?); 

} 
. 
. 
. 

Ich konnte nicht ein Verfahren zur Herstellung resttemplate finden, die mit Anfrage und Antwort Objekten funktionieren.

Ich habe auch versucht Federumleitung und weiterleiten. Aber redirect ändert nicht die Client-IP-Adresse der Anfrage, so denke ich, dass es in diesem Fall nutzlos ist. Ich könnte auch nicht zu einer anderen URL weiterleiten.

Gibt es einen geeigneteren Weg, dies zu erreichen? Vielen Dank im Voraus.

+2

Warum konnte man nicht so etwas wie Apache verwendet w/mod_rewrite oder mod_proxy dies zu tun? Sie würden im Grunde einen Webserver außerhalb Ihrer Firewall (normalerweise nennen wir das die DMZ) und Setup-Regeln in der FW, die es diesem Server ermöglicht, mit Ihrem Server hinter der Firewall zu sprechen. So lösen die meisten Unternehmen dieses Problem. – CodeChimp

+0

danke, ich werde versuchen, mit sys Admins zu sprechen, wenn Ihre Lösung für unseren Fall funktioniert. Unterdessen benutze ich resttemplate und serialize/deserialize json Daten zum Zeichenkette. – nilgun

Antwort

39

Sie spiegeln/Proxy alle Anfragen mit diesem:

private String server = "localhost"; 
private int port = 8080; 

@RequestMapping("/**") 
@ResponseBody 
public String mirrorRest(@RequestBody String body, HttpMethod method, HttpServletRequest request, 
    HttpServletResponse response) 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(); 
} 

Dies wird keinen Header spiegeln.

+0

Ich erwartete eine Antwort wie deine, aber es ist lange Zeit gewesen und ich arbeite nicht mehr an diesem Projekt. Leider ist es mir nicht möglich, umfangreiche Tests durchzuführen und den Code sofort zu bestätigen. – nilgun

+0

Wie würden die URL und die Parameter für diesen Controller aussehen? Ich habe die richtige URL aufgerufen, aber ich bekomme "die vom Client gesendete Anfrage war syntaktisch falsch"? – WowBow

+0

Meine ursprüngliche Methode Signatur sieht wie folgt aus (ich nicht RequestBody hatte überhaupt oder Httpmethod) @RequestMapping ("/ getProduct") öffentlichen CustomMessage getCompanyResults (@RequestParam ("search") String-Suche, @RequestParam (Wert = "id", required = false) String rfgId, @RequestParam (Wert = "rowBegin", required = false) String) – WowBow

4

Mit Netflix Zuul können Sie Anfragen, die an eine Federanwendung gesendet werden, an eine andere Federanwendung weiterleiten.

Angenommen, Sie haben zwei Anwendungs ​​haben: 1.songs-App, 2.api-Gateway

Im api-Gateway-Anwendung, fügen Sie zuerst die zuul dependecy, dann können Sie einfach Ihre Routing-Regel in der Anwendung definieren. yml wie folgt:

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/ 

und schließlich die api-Gateway-Anwendung laufen wie:

@EnableZuulProxy 
@SpringBootApplication 
public class Application { 
    public static void main(String[] args) { 
     SpringApplication.run(Application.class, args); 
    } 
} 

Nun wird das Gateway leitet die alle /api/songs/ Anfragen an http://localhost:8081/songs/.

Ein Arbeitsbeispiel ist hier: https://github.com/muatik/spring-playground/tree/master/spring-api-gateway

Eine weitere Ressource: http://www.baeldung.com/spring-rest-with-zuul-proxy

Verwandte Themen