wake-up-neo.com

spring MVC Rest Service Weiterleitung/Vorwärts/Proxy

Ich habe eine Webanwendung erstellt, die Spring-MVC-Framework zur Veröffentlichung von REST -Diensten ..__ verwendet. Beispiel:

@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 haben keinen direkten Zugriff auf den Computer, auf dem sich die Anwendung befindet (Es gibt eine Firewall). Daher brauche ich eine Umleitungsschicht auf einer Proxy-Maschine (auf die die Clients zugreifen können), die den eigentlichen Ruhedienst aufruft.

Ich habe versucht, einen neuen Aufruf mit RestTemplate: .__ zu erstellen. 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);

}

Dies ist in Ordnung, aber ich muss jede Methode im Controller neu schreiben, um das resttemplate verwenden zu können. Dies führt auch zu einer redundanten Serialisierung/Deserialisierung auf der Proxy-Maschine. 

Ich habe versucht, eine generische Funktion mit 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 keine Methode von resttemplate finden, die mit Anforderungs- und Antwortobjekten funktioniert.

Ich habe auch Spring-Weiterleitung und Weiterleiten versucht. Die Weiterleitung ändert jedoch nicht die Client-IP-Adresse der Anforderung, daher denke ich, dass sie in diesem Fall unbrauchbar ist. Ich konnte auch nicht an eine andere URL weiterleiten.

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

39
nilgun

Sie können alle Anfragen damit spiegeln/proxy:

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();
}

Dies wird keine Header spiegeln.

51
koe

Sie können Netflix Zuul verwenden, um Anforderungen, die an eine Federanwendung kommen, an eine andere Federanwendung weiterzuleiten.

Nehmen wir an, Sie haben zwei Anwendungen: 1.Songs-App, 2.API-Gateway

Fügen Sie in der API-Gateway-Anwendung zunächst die zuul-abhängige Datei hinzu. Anschließend können Sie Ihre Routing-Regel in application.yml wie folgt definieren:

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 wie folgt ausführen:

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

Nun leitet das Gateway alle /api/songs/-Anforderungen an http://localhost:8081/songs/ weiter. 

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

13
Muatik

Hier ist meine modifizierte Version der ursprünglichen Antwort, die sich in vier Punkten unterscheidet:

  1. Der Anforderungshauptteil wird nicht obligatorisch, und GET-Anforderungen können daher nicht fehlschlagen.
  2. Es kopiert alle in der ursprünglichen Anforderung vorhandenen Header. Wenn Sie einen anderen Proxy-/Webserver verwenden, kann dies aufgrund der Komprimierung der Inhaltslänge/gzip zu Problemen führen. Beschränken Sie die Header auf die, die Sie wirklich benötigen. 
  3. Die Abfrageparameter oder der Pfad werden nicht mit nicht neu codiert. Wir erwarten, dass sie trotzdem verschlüsselt werden. Beachten Sie, dass andere Teile Ihrer URL möglicherweise auch codiert sind. Wenn dies für Sie der Fall ist, nutzen Sie das volle Potenzial von UriComponentsBuilder.
  4. Fehlercodes werden vom Server ordnungsgemäß zurückgegeben. 

@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());
    }
}
7
Veluria

Wenn Sie eine untergeordnete Lösung wie mod_proxy verwenden können, wäre dies der einfachere Weg. Wenn Sie jedoch mehr Kontrolle benötigen (z. B. Sicherheit, Übersetzung, Geschäftslogik), sollten Sie sich Apache Camel ansehen: http://camel.Apache.org/how-to-use-camel-as-a-http-proxy-zwischen-a-client-und-server.html

1
Chris H.

proxy-Controller mit 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);
    }


0
love adu

Sie benötigen etwas wie jetty transparent proxy, das Ihren Anruf tatsächlich umleitet, und Sie haben die Möglichkeit, die Anforderung bei Bedarf zu überschreiben. Sie finden die Details unter http://reanimatter.com/2016/01/25/embedded-jetty-as-http-proxy/

0
krmanish007