「java.net.URIで扱えるホスト名はRFC 2396 (RFC 3986じゃない・・)」を投稿するきっかけとなったSpring WebのCORS(Cross-Origin Resource Sharing)機能のエラーは、Spring Frameworkのバグでした・・・
バグ内容は、SPR-14305を参照してくだい。
なお、このバグは、最新の開発ライン(投稿時点では未リリース)であるSpring Framework 4.3(Spring Boot 1.4)では既に解消されており、Spring Framework 4.2.7.RELEASEへバックポートされる予定です。
環境
- Java SE 8
- Spring Framework 4.2.6.RELEASE(Spring Boot 1.3.5.RELEASE)
事象
リクエストにOriginヘッダーがあるとCORS(Cross-Origin Resource Sharing)関連の処理が動き、その処理の中でリクエストURLをjava.net.URI
に変換するロジックがあります。URI
クラスはRFC 3986に対応していないため、例えばリクエストURLが「 http://spring_app/
」だとホスト名がnull
になり、Spring側の処理の中でNPEが発生しています。
...
2016-05-25 04:46:48.890 ERROR 84097 --- [io-8080-exec-10] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause
java.lang.NullPointerException: null
at org.springframework.web.util.WebUtils.isSameOrigin(WebUtils.java:816) ~[spring-web-4.2.6.RELEASE.jar:4.2.6.RELEASE]
at org.springframework.web.cors.DefaultCorsProcessor.processRequest(DefaultCorsProcessor.java:76) ~[spring-web-4.2.6.RELEASE.jar:4.2.6.RELEASE]
at org.springframework.web.servlet.handler.AbstractHandlerMapping$CorsInterceptor.preHandle(AbstractHandlerMapping.java:503) ~[spring-webmvc-4.2.6.RELEASE.jar:4.2.6.RELEASE]
at org.springframework.web.servlet.HandlerExecutionChain.applyPreHandle(HandlerExecutionChain.java:134) ~[spring-webmvc-4.2.6.RELEASE.jar:4.2.6.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:956) ~[spring-webmvc-4.2.6.RELEASE.jar:4.2.6.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:895) ~[spring-webmvc-4.2.6.RELEASE.jar:4.2.6.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:967) ~[spring-webmvc-4.2.6.RELEASE.jar:4.2.6.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:858) ~[spring-webmvc-4.2.6.RELEASE.jar:4.2.6.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:622) ~[tomcat-embed-core-8.0.33.jar:8.0.33]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:843) ~[spring-webmvc-4.2.6.RELEASE.jar:4.2.6.RELEASE]
...
この事象を再現するプロジェクトは、https://github.com/spring-projects/spring-framework-issues/blob/master/SPR-14305/ にあります。具体的な発生条件は、 テストコード ReproTests.javaをごらんください。
対処方法
基本的には・・・
Spring Framework 4.3.0(2016/6/8リリース予定) or 4.2.7(2016/7/20リリース予定)がリリースされるのを待ちましょう!!
どうしてもリリースを待てない場合は、org.springframework.web.cors.DefaultCorsProcessor
のprocessRequest
メソッドをオーバーライドし、拡張したクラスをSpring MVC(AbstractHandlerMapping
のcorsProcessor
プロパティ)に適用することでエラーを回避することは可能です。
まとめ
今回の事象はSpringのバグでしたが、Javaのjava.net.URI
クラスがRFC 3986に対応していないことがそもそもの原因です・・・。RFC 3986サポート用のIssueはあがっているようですが、残念ながら完全に放置状態です
今回のように使用しているライブラリにバグや改善の余地がある場合は、オレオレ拡張などで個別(アドホック)に対応するのではなく、ライブラリ側にIssueをあげてライブラリ本家に取り込んでもらえるように働きかけるようにしましょう!!!