しおしお

IntelliJ IDEAのことなんかを書いてます

Spring Boot(MVC)でCORSを色々試してみた

雰囲気でCORSの設定してたので設定によってどんな結果になるか調べてみたよ。

クライアントとサーバのコード

クライアント

  • getとpostを行うだけの簡単なhtmlを使って試してみます
  • IntelliJさんについている簡易サーバからSpring Bootなアプリケーションにリクエストを投げる感じにします
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
  <script
      src="https://code.jquery.com/jquery-3.4.1.min.js"
      integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo="
      crossorigin="anonymous"></script>
  <script>
    $(document).ready(function () {
      $('#get').click(function () {
        axios.get('http://localhost:8080/hello')
            .then(function (response) {
              console.log('get', response.status, response.data);
            });
      })
      
      $('#post').click(function () {
        axios.post('http://localhost:8080/hello', {
          id: 1,
          text: 'hello'
        })
            .then(function (response) { 
              console.log('post', response.status)
            })
      })
    });
  </script>
</head>
<body>
<button id="get">GET</button>
<button id="post">POST</button>
</body>
</html>

サーバ

  • getとpostのリクエストを簡単に処理するだけのやつです
@RestController
@RequestMapping("/hello")
class HelloController {

    @GetMapping
    fun get(): String {
        return "hello"
    }

    @PostMapping
    fun post(@RequestBody body: Body) {
        println("body = ${body}")
    }

    data class Body(
            private val text: String
    )
}

何も設定を行わずにクライアントからリクエストを投げてみる

デフォルト状態で、異なるドメインからリクエスト投げるとこんな感じにエラーになりますね。 f:id:sioiri:20190611090037p:plain

Controllerに@CrossOriginアノテーションを設定してみる

Controllerに対して、@CrossOriginアノテーションを設定すると、Controller毎に細かく設定ができます。 また、ハンドラメソッドに対して設定した場合には、より細かく設定できるようになります。

Controllerにアノテーションを設定した場合

Controllerクラスに@CrossOriginアノテーションを設定すると、このController内のハンドラメソッドがすべて許可されるようになります。 @CrossOriginvalue(origins)allowedHeadersを設定することで、より細かな設定もできるようになっています。

@RestController
@RequestMapping("/hello")
@CrossOrigin
class HelloController {
  // 省略
}

実行結果

@CrossOriginアノテーションを設定したことで、ちゃんと異なるドメインからの要求が処理されるようになりました。 f:id:sioiri:20190611095406p:plain

ハンドラメソッドにアノテーションを設定した場合

ハンドラメソッドに@CrossOriginアノテーションを設定すると、そのリクエストのみ許可されるようになります。 もし、Controllerにも設定されていた場合、Controllerとハンドラメソッドの設定がマージされる感じになります。

@RestController
@RequestMapping("/hello")
class HelloController {

    @GetMapping
    fun get(): String {
        return "hello"
    }

    @PostMapping
    @CrossOrigin
    fun post(@RequestBody body: Body) {
        println("body = ${body}")
    }

    data class Body(
            private val id: Int,
            private val text: String
    )
}

実行結果

今回は、POSTの処理だけに@CrossOriginアノテーションを設定したので、POST処理だけ成功しています。 f:id:sioiri:20190611093124p:plain

WebMvcConfigurerを使って横断的に設定してみる

WebMvcConfigurer#addCorsMappings を使うと、アプリケーション全体に対して設定を行うことができるようになります。 デフォルトでは、GET、HEAD、POSTしか許可されていないので、それ以外を許可する場合には allowedMethods を設定して上げる必要があります。

設定は、こんな感じにWebMvcConfigurerのBeanを登録してあげるだけですね。

@Configuration
class WebConfig {
    @Bean
    fun config(): WebMvcConfigurer {
        return object: WebMvcConfigurer {
            override fun addCorsMappings(registry: CorsRegistry) {
                registry.addMapping("/**")
                        .allowedOrigins("http://localhost:63342")
                        .allowedMethods("GET", "POST", "PUT")
            }
        }
    }
}

実行結果

個別のControllerに@CrossOriginアノテーションを設定しなくても処理が成功するようになりました。
f:id:sioiri:20190611095214p:plain