【问题标题】:How do you handle adding a CORS header in a Spring Boot server with graphql-kotlin?如何使用 graphql-kotlin 在 Spring Boot 服务器中添加 CORS 标头?
【发布时间】:2020-04-23 14:01:29
【问题描述】:

我正在使用由 Expedia 创建和开源的GraphQL Kotlin library 构建一个简单的 Spring Server 项目。我有一个正在运行的后端,正在与数据存储区通信,并且我能够通过 Playground 发送查询来获取数据。

当我尝试从我的 React 前端(使用 Apollo)连接时,由于 CORS 问题,初始 OPTIONS 请求会收到 404 响应。我对 Spring Boot 比较陌生,在 SO 和其他地方记录了很多潜在的方法。

如何拦截响应并添加适当的 Access-Control-Allow-Origin 标头?

【问题讨论】:

    标签: spring-boot kotlin cors graphql-kotlin


    【解决方案1】:

    在尝试了上述许多方法后,我找到了一种适用于我的特定变量组合的方法。

    例如,这些不起作用:

    1. 覆盖addCorsMappings的WebFluxConfigurer组件 功能
    2. @CrossOrigin查询函数上的注解
    3. 将 spring boot actuator lib 添加到项目中,并将 management.endpoints.web.cors 配置添加到 application.yml,每 the Spring documentation

    根据这个 SO 问题,最终对我有用的是自定义 WebFilter 子类:Enable CORS in Spring 5 Webflux?

    还有this tutorial,它详细说明了 Spring Boot 的一般工作原理。

    【讨论】:

      【解决方案2】:

      你可以这样做:

       @Bean
          @Profile("!production")
          fun corsFilter(): CorsWebFilter = CorsWebFilter(
              UrlBasedCorsConfigurationSource().apply {
                  registerCorsConfiguration(
                      "/**",
                      CorsConfiguration().apply {
                          allowCredentials = true
                          allowedOrigins = listOf("*")
                          allowedHeaders = listOf("*")
                          allowedMethods = listOf("*")
                      }
                  )
              }
          )
      

      【讨论】:

        【解决方案3】:

        对我来说(使用与您相同的技术),创建自定义过滤器组件 (CorsFilter) 是所有其他选项中效果最好的:

        我的配置示例:

        @Component
        class CorsFilter: WebFilter {
        
            @Value("\${cors.allowed_origin}")
            lateinit var allowedOrigin: String
        
            override fun filter(ctx: ServerWebExchange, chain: WebFilterChain): Mono<Void> {
                ctx.response.headers.add("Access-Control-Allow-Origin", allowedOrigin)
                ctx.response.headers.add("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE, OPTIONS")
                ctx.response.headers.add("Access-Control-Allow-Credentials", "true")
                ctx.response.headers.add("Access-Control-Allow-Headers", "DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range, Authorization")
                return when {
                    ctx.request.method == HttpMethod.OPTIONS -> {
                        ctx.response.headers.add("Access-Control-Max-Age", "1728000")
                        ctx.response.statusCode = HttpStatus.NO_CONTENT
                        Mono.empty()
                    }
                    else -> {
                        ctx.response.headers.add("Access-Control-Expose-Headers", "DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range")
                        chain.filter(ctx)
                    }
                }
            }
        }
        

        注意:allowedOrigin 变量取自 applications.properties 文件

        【讨论】:

          【解决方案4】:

          只有在 spring boot-kotlin 服务器中添加下一个配置才能使用 React 和 Apollo:

          import org.springframework.context.annotation.Bean
          import org.springframework.context.annotation.Configuration
          import org.springframework.http.HttpMethod
          import org.springframework.http.HttpStatus
          import org.springframework.web.cors.reactive.CorsUtils
          import org.springframework.web.server.WebFilter
          import reactor.core.publisher.Mono
          
          @Configuration
          class ReactiveConfigurations {
          
              companion object {
                  const val ALLOWED_HEADERS = "x-requested-with, authorization, Content-Type, Authorization, credential, X-XSRF-TOKEN"
                  const val ALLOWED_METHODS = "GET, PUT, POST, DELETE, OPTIONS"
                  const val ALLOWED_ORIGIN = "*"
                  const val MAX_AGE = "3600"
              }
          
              @Bean
              fun corsFilter(): WebFilter {
                  return WebFilter { ctx, chain ->
                      val request = ctx.request
                      if (CorsUtils.isCorsRequest(request)) {
                          val response = ctx.response
                          val headers = response.headers
                          headers.add("Access-Control-Allow-Origin", ALLOWED_ORIGIN)
                          headers.add("Access-Control-Allow-Methods", ALLOWED_METHODS)
                          headers.add("Access-Control-Max-Age", MAX_AGE)
                          headers.add("Access-Control-Allow-Headers", ALLOWED_HEADERS)
                          if (request.method === HttpMethod.OPTIONS) {
                              response.statusCode = HttpStatus.OK
                              return@WebFilter Mono.empty<Void>()
                          }
                      }
                      chain.filter(ctx)
                  }
              }
          }
          
          

          【讨论】:

            猜你喜欢
            • 2018-07-19
            • 2016-02-15
            • 2020-11-09
            • 2018-06-03
            • 1970-01-01
            • 2017-05-07
            • 2020-05-16
            • 2023-01-23
            • 2018-12-22
            相关资源
            最近更新 更多