如何使用 graphql-kotlin 在 Spring Boot 服务器中添加 CORS 标头?

Posted

技术标签:

【中文标题】如何使用 graphql-kotlin 在 Spring Boot 服务器中添加 CORS 标头?【英文标题】:How do you handle adding a CORS header in a Spring Boot server with graphql-kotlin? 【发布时间】: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 标头?

【问题讨论】:

【参考方案1】:

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

例如,这些不起作用:

    覆盖addCorsMappings的WebFluxConfigurer组件 功能 @CrossOrigin查询函数上的注解 将 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)
        
    


【讨论】:

以上是关于如何使用 graphql-kotlin 在 Spring Boot 服务器中添加 CORS 标头?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用带有 ktor 框架的 graphql-kotlin 进行字段级解析器

十 如何应用设计原则

Pygame错误:self.spritedict [spr] = surface_blit(spr.image,spr.rect)

使用Spire组件抛出异常The type initializer for 'spr857' threw an exception

我的大学,我的SPR

Aurora 极光 A21超算将会使用SPR CPU和Ponte Vecchio GPU