您如何使用 graphql-kotlin 在 Spring 引导服务器中添加 CORS header?
How do you handle adding a CORS header in a Spring Boot server with graphql-kotlin?
我正在使用由 Expedia 创建的 GraphQL Kotlin library & open-sourced 构建一个简单的 Spring 服务器项目。我有一个后端和 运行,与数据存储对话,我可以通过 Playground 发送查询来获取数据。
当我尝试从我的 React 前端(使用 Apollo)连接时,由于 CORS 问题,初始 OPTIONS 请求收到 404 响应。我对 Spring Boot 比较陌生,SO 和其他地方记录了很多潜在的方法。
如何拦截响应并添加适当的 Access-Control-Allow-Origin header?
在尝试了上述许多方法之后,我找到了一种适用于我的特定变量组合的方法。
例如,这些无效:
- 覆盖
addCorsMappings
的 WebFluxConfigurer 组件
函数
@CrossOrigin
查询函数注释
- 将 spring 引导执行器库添加到项目并将 management.endpoints.web.cors 配置添加到 application.yml,根据 the Spring documentation
根据这个 SO 问题,最终对我有用的是自定义 WebFilter 子类:
还有 this tutorial,这说明了很多 Spring Boot 的一般工作方式。
仅在 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)
}
}
}
你可以这样做:
@Bean
@Profile("!production")
fun corsFilter(): CorsWebFilter = CorsWebFilter(
UrlBasedCorsConfigurationSource().apply {
registerCorsConfiguration(
"/**",
CorsConfiguration().apply {
allowCredentials = true
allowedOrigins = listOf("*")
allowedHeaders = listOf("*")
allowedMethods = listOf("*")
}
)
}
)
对我来说(使用与您相同的技术),创建自定义过滤器组件 (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 个文件
我正在使用由 Expedia 创建的 GraphQL Kotlin library & open-sourced 构建一个简单的 Spring 服务器项目。我有一个后端和 运行,与数据存储对话,我可以通过 Playground 发送查询来获取数据。
当我尝试从我的 React 前端(使用 Apollo)连接时,由于 CORS 问题,初始 OPTIONS 请求收到 404 响应。我对 Spring Boot 比较陌生,SO 和其他地方记录了很多潜在的方法。
如何拦截响应并添加适当的 Access-Control-Allow-Origin header?
在尝试了上述许多方法之后,我找到了一种适用于我的特定变量组合的方法。
例如,这些无效:
- 覆盖
addCorsMappings
的 WebFluxConfigurer 组件 函数 @CrossOrigin
查询函数注释- 将 spring 引导执行器库添加到项目并将 management.endpoints.web.cors 配置添加到 application.yml,根据 the Spring documentation
根据这个 SO 问题,最终对我有用的是自定义 WebFilter 子类:
还有 this tutorial,这说明了很多 Spring Boot 的一般工作方式。
仅在 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)
}
}
}
你可以这样做:
@Bean
@Profile("!production")
fun corsFilter(): CorsWebFilter = CorsWebFilter(
UrlBasedCorsConfigurationSource().apply {
registerCorsConfiguration(
"/**",
CorsConfiguration().apply {
allowCredentials = true
allowedOrigins = listOf("*")
allowedHeaders = listOf("*")
allowedMethods = listOf("*")
}
)
}
)
对我来说(使用与您相同的技术),创建自定义过滤器组件 (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 个文件