CORS三问

复制代码
Access to XMLHttpRequest at 'http://localhost:7777/dev-api/renren-fast/sys/login' from origin 'http://localhost:8001' 
has been blocked by CORS policy: 
Response to preflight request doesn't pass access control check: 
No 'Access-Control-Allow-Origin' header is present on the requested resource.

前端开发者经常会被这个问题困扰. 下面就来讲个这个问题.

  1. 是什么
  2. 为什么
  3. 怎么办
    3.1 vue
    3.2 nginx
    3.3 springmvc
    3.4 gateway

1. CORS本质

复制代码
跨源资源共享(CORS,或通俗地译为跨域资源共享)是一种基于 HTTP 头的机制,
该机制通过允许服务器标示除了它自己以外的其他源(域、协议或端口),
使得浏览器允许这些源访问加载自己的资源。
跨源资源共享还通过一种机制来检查服务器是否会允许要发送的真实请求,
该机制通过浏览器发起一个到服务器托管的跨源资源的"预检"请求。
在预检中,浏览器发送的头中标示有 HTTP 方法和真实请求中会用到的头。

发生跨域的条件

简单来讲就是网络访问跨域了. 默认只能进行同源访问. 只要协议、主机、端口有一个不同, 就会跨域.

  1. http https 跨域
  2. baidu.com 39.156.66.10 域名\ip跨域
  3. 主域相同,子域不同 www.a.com script.a.com 跨域
  4. 测试的时候, localhost\127.0.0.1 也会出现跨域

允许跨域的请求---简单请求

并不是所有的跨域都会默认被拦截.

简单get、head、post(Content-Type 限定为text/plain、multipart/form-data、application/x-www-form-urlencoded)并且没有设置自定义请求头, 默认不会被拦截.

了解详情

跨域请求的交互方式

相对于简单请求, 跨域请求会先发送一个options请求.
相当于询问服务器, 我能进行XX请求吗? 请求地址、请求头(有点像函数签名)

针对options请求, 服务端添加一些特有的响应头.

2. 浏览器为什么要限制跨域

出于安全性,浏览器限制脚本内发起的跨源 HTTP 请求。

3. 解决方案

1. vue配置代理

这种在开发式比较常用, 一般在vue.config.js中配置

复制代码
    module.exports = {
    devServer: {
        proxy: {
            '/proxyApi': {
              target: 'http://demo.renren.io/renren-fast/, // 目标服务器
                changeOrigin: true,   // 是否改变源
                pathRewrite: { '^/proxyApi': '' }  // 路径重写

            }

        }

    }

};

2. nginx 处理

部署在同一个域

将前端项目和后端项目放在一起,作为同一个域,当然不存在跨域的问题.

nginx 配置cors

复制代码
    location /dev-api/ {
    # 预见请求,单独处理
		if ($request_method = 'OPTIONS') {
			add_header 'Access-Control-Allow-Origin' 'http://localhost:8001';
			add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
			add_header 'Access-Control-Allow-Credentials' 'true';
			add_header 'Access-Control-Allow-Headers' 'token,DNT,X-CustomHeader,Keep-Alive,
			User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type
			,Authorization';
			# add_header 'Access-Control-Allow-Headers' '*';  preflight response not support *.
			add_header 'Access-Control-Max-Age' 1728000;
			add_header 'Content-Type' 'text/plain charset=UTF-8';
			add_header 'Content-Length' 0;
			return 204;
		}
    # 其他请求  post  get  ...
	
  		proxy_pass http://127.0.0.1:18080/;
		
		add_header 'Access-Control-Allow-Origin' 'http://localhost:8001';

        add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS';

		add_header 'Access-Control-Allow-Headers' '*'; # ok
		add_header 'Access-Control-Allow-Credentials' 'true';

  	}

根据项目不同会有不同的提示. 根据提示进行add_header参数的调整即可.
这个说的是options(preflight response)响应中 Access-Control-Allow-Headers 没有content-type.

这个说的是options(preflight response)响应中 Access-Control-Allow-Origin 没有设置.(ps. 这个只能写具体的域)

这个说的是options(preflight response)响应中 Access-Control-Allow-Headers 没有token.

重要的是不要紧张,一步步调试分析.

3. springmvc 配置

复制代码
package io.renren.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class CorsConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOriginPatterns("*")
                .allowCredentials(true)
                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
                .maxAge(3600);
    }
}

添加上述代码, 进行自动注入即可.

看网上的答案,有的没有写options方法,那肯定不对.

4. gateway 配置

对于使用gateway的项目, 需要将内部项目的cors配置去掉. 否则会进行重复添加.

添加如下代码,配置跨域.

复制代码
package com.atguigu.gulimail.gateway.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;

import java.util.Arrays;

@Configuration
public class CorsConfig {

    @Bean
    public CorsWebFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();

        // 允许的来源域名
        config.setAllowedOriginPatterns(Arrays.asList(
                "http://localhost:8001"  // 前端请求的域名
//            "https://localhost:10086" // 后端服务的域名
        ));
        // 允许的请求方法
        config.addAllowedMethod("*");

        // 允许的请求头
        config.addAllowedHeader("*");

        // 允许携带凭证(如 cookies)
        config.setAllowCredentials(true);

        // 允许的响应头
        config.addExposedHeader("*");

        // 预检请求的有效期
        config.setMaxAge(3600L);

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        // 应用 CORS 配置到所有路径
        source.registerCorsConfiguration("/**", config);

        return new CorsWebFilter(source);
    }
}

参考内容

mozilla cors

谷粒商城

相关推荐
知识分享小能手2 小时前
React学习教程,从入门到精通,React AJAX 语法知识点与案例详解(18)
前端·javascript·vue.js·学习·react.js·ajax·vue3
朗迹 - 张伟3 小时前
Gin-Vue-Admin学习笔记
vue.js·学习·gin
古夕3 小时前
前端文件下载的三种方式:a标签、Blob、ArrayBuffer
前端·javascript·vue.js
武昌库里写JAVA3 小时前
Java设计模式中的几种常用设计模式
vue.js·spring boot·sql·layui·课程设计
wow_DG5 小时前
【Vue2 ✨】Vue2 入门之旅 · 进阶篇(九):Vue2 性能优化
javascript·vue.js·性能优化
一 乐6 小时前
美食分享|基于Springboot和vue的地方美食分享网站系统设计与实现(源码+数据库+文档)
java·vue.js·spring boot·论文·毕设·美食·地方美食分享网站系统
我是日安7 小时前
从零到一打造 Vue3 响应式系统 Day 4 - 核心概念:收集依赖、触发更新
前端·vue.js
wow_DG8 小时前
【Vue2 ✨】Vue2 入门之旅 · 进阶篇(八):Vuex 内部机制
前端·javascript·vue.js
若年封尘8 小时前
吃透 Vue 样式穿透:从 scoped 原理到组件库样式修改实战
前端·javascript·vue.js·样式穿透·scoped