RESTサービスを公開するために、Spring MVCフレームワークを使用して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);
}
ここで、アプリケーションを展開する必要がありますが、次の問題があります。クライアントは、アプリケーションが存在するコンピューターに直接アクセスできません(ファイアウォールがあります)。したがって、実際の休憩サービスを呼び出すプロキシマシン(クライアントからアクセス可能)にリダイレクトレイヤーが必要です。
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アドレスを変更しないため、この場合は役に立たないと思います。別のURLにも転送できませんでした。
これを達成するためのより適切な方法はありますか?前もって感謝します。
これですべてのリクエストをミラーリング/プロキシできます:
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を使用して、スプリングアプリケーションに着信するリクエストを別のスプリングアプリケーションにルーティングできます。
2つのアプリケーションがあるとします:1.songs-app、2.api-gateway
Api-gatewayアプリケーションで、最初に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-gatewayアプリケーションを次のように実行します。
@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
以下に、元の回答の修正版を示します。これは4つの点で異なります。
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());
}
}
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);
}
Mod_proxyのような低レベルのソリューションを使用して回避できる場合は、より簡単な方法ですが、より多くの制御(セキュリティ、翻訳、ビジネスロジックなど)が必要な場合は、Apache Camelを見てください。 http://camel.Apache.org/how-to-use-camel-as-a-http-proxy-between-a-client-and-server.html
実際に呼び出しをリダイレクトするjetty transparent proxy
のようなものが必要であり、必要に応じてリクエストを上書きする機会があります。詳細は http://reanimatter.com/2016/01/25/embedded-jetty-as-http-proxy/ で入手できます。