概要
プロキシサーバーを利用してインターネットにアクセスするネットワーク環境下でSpringのRestTemplateを利用して、外部のAPIにリクエストを送信しようとしたところエラーが発生しました。
普段開発する環境ではプロキシサーバーを利用しておらず調査に時間がかかったので、今回対応した方法をメモしておきます。
発生した事象
プロキシサーバーを利用してインターネットにアクセスするネットワーク環境下でRestTemplate.exchange
を利用して外部APIを利用してGETリクエストをしたところ下記のエラーが発生。
ただし、同じAPIをブラウザ(Chrome)でアクセスした際にはレスポンスがきちんと返ってきている状況でした。
エラーメッセージ
org.springframework.web.client.ResourceAccessException: I/O error on GET request for "{targetURL}":
Connection refused: connect;
nested exception is java.net.ConnectException: Connection refused: connect
イメージ図(ネットワーク環境)
原因
ブラウザはホストサーバーのプロキシ設定を利用していたため、インターネットアクセス時にはプロキシサーバーを経由してアクセスできていましたが、SpringBootアプリケーション側ではリクエスト時にプロキシサーバーを経由できていませんでした。
SpringBootアプリケーション側では明示的に設定ファイルや実行時引数でプロキシ設定を行わないとプロキシサーバーをいけないようです。
SpringBootアプリケーションでプロキシ設定をする方法
1. System.setPropertyの利用
// このケースではプロキシサーバーとして webcache.example.com:8080 を利用
// httpsの場合はhttps.proxyHost, https.proxyPortを利用します
System.setProperty("http.proxyHost", "webcache.example.com");
System.setProperty("http.proxyPort", "8080");
2. JVM起動時の引数として指定
Springアプリケーションの実行時引数として指定します
java ./application.jar -Dhttp.proxyHost=webcache.example.com -Dhttp.proxyPort=8080
3. RestTemplateのインスタンス作成時factoryを利用して設定
1,2の方法だとシステム全体に影響を与えるので、影響範囲を限定したい場合にはこちらの方法を利用します。
//ここでプロキシ設定を行う
Proxy proxy = new Proxy(Type.HTTP, new InetSocketAddress(PROXY_SERVER_HOST, PROXY_SERVER_PORT));
// RestTermplate用にプロキシ設定をするClientHttpRequestFactoryを用意する
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setProxy(proxy);
RestTemplate restTemplate = new RestTemplate(requestFactory);
// こちらのRestTemplateを利用してHTTP(S)通信を行う
参考リンク
- [RestTemplate による HTTP 通信の際に発生する様々なエラー (例外) を処理する]
(https://qiita.com/niwasawa/items/8647e8891954a88373be) - Java ネットワークとプロキシ
- Proxies With RestTemplat
- Spring の RestTemplate のプロキシ設定