跨域访问
问题
使用Vue对后台的资源进行访问,发生跨域的请求,会产生如下的报错
Access to fetch at ‘http://localhost:8080/hdfs/read-csv?path=/output/hdfsJobByMonth/part-r-00000‘ from origin ‘http://localhost:9528‘ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource. If an opaque response serves your needs, set the request’s mode to ‘no-cors’ to fetch the resource with CORS disabled.
这个错误表明前端应用(运行在 http://localhost:9528)试图通过 fetch API 访问后端服务(运行在 http://localhost:8080)的某个资源,但是由于跨域资源共享(CORS)策略的限制,这个请求被浏览器阻止了
CORS 策略要求服务器在响应中包含一些特定的 HTTP 头信息,比如 Access-Control-Allow-Origin
,来告诉浏览器哪些源(即哪些域、协议和端口)有权访问该资源。在这个例子中,服务器没有在响应中包含这个必要的头信息。
要解决这个问题,有几种解决办法:
配置后端服务以支持 CORS:
在后端服务(http://localhost:8080
)上添加 CORS 支持。这通常意味着在响应中包含适当的 HTTP 头,如Access-Control-Allow-Origin: *
(允许所有源)或Access-Control-Allow-Origin: http://localhost:9528
(仅允许来自http://localhost:9528
的请求)。但是请注意,将Access-Control-Allow-Origin
设置为*
可能会带来安全风险,特别是如果服务涉及敏感数据。使用代理服务器:
可以在前端应用中设置一个代理服务器,该服务器将请求转发到后端服务,并在转发响应时添加 CORS 头。这通常可以通过配置开发服务器(如 webpack-dev-server、Create React App 的开发服务器等)来实现。使用
no-cors
模式(不推荐):
可以将 fetch 请求的模式设置为no-cors
来绕过 CORS 策略,但这将导致响应变得不透明(opaque),前端无法读取响应的内容。因此,这通常不是一个好的解决方案,除非确实不需要读取响应的内容。在本地开发时禁用浏览器的 CORS 检查:
这可以通过在浏览器中使用插件或特殊模式来实现,但请注意,这只是一个临时的解决方案,并且不应该在生产环境中使用,因为它会暴露应用于安全风险。使用 JSONP(如果适用):
如果后端服务支持 JSONP,并且只是想获取 JSON 数据,那么可以使用 JSONP 来绕过 CORS 策略。但是,JSONP 有一些限制,比如它只支持 GET 请求,并且只能返回 JSONP 格式的响应。
解决
使用第一种方式,在后端服务配置允许跨域访问
如下有几种方式:
方法一:全局CORS配置
可以通过配置类中添加一个WebMvcConfigurer
bean来全局配置CORS。
1 | import org.springframework.context.annotation.Configuration; |
方法二:使用@CrossOrigin
注解
也可以在Controller类或者特定的方法上使用@CrossOrigin
注解来启用CORS。
1 | import org.springframework.web.bind.annotation.CrossOrigin; |
方法三:自定义CORS过滤器
需要更复杂的CORS配置,可以创建一个自定义的CORS过滤器。
1 | import org.springframework.core.Ordered; |
注意事项
- 当使用
allowedOrigins
时,如果只想允许来自特定域名的请求,就指定那个域名。如果想允许来自任何域名的请求(注意:这可能会带来安全风险),可以使用"*"
。 allowCredentials(true)
允许跨域请求携带认证信息(如cookies),但这要求Access-Control-Allow-Origin
不能是"*"
,而必须是一个明确的域名。- 如果前端应用需要处理预检请求(OPTIONS请求),确保后端配置也支持这些请求。预检请求是浏览器在发送实际请求之前发送的,以检查服务器是否允许跨域请求。