跨域_Cross-origin resource sharing

同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个ip,也非同源

1.什么是CORS?

CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。

2.简单请求和复杂请求的区别

2.1.简单请求

(1)请求方法是以下三种方法之一:

HEAD、 GET、POST

(2)HTTP的头信息不超出以下几种字段:

Accept

Accept-Language

Content-Language

Last-Event-ID

Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

当浏览器发现发起的ajax请求是简单请求时,会在请求头中携带一个字段:Origin.

Origin中会指出当前请求 属于哪个域(协议+域名+端口)和Request URL进行对比。服务会根据这个值决定是否允许其跨域。

如果服务器允许跨域,需要在返回的响应头 中携带下面信息:

Access-Control-Allow-Origin: http://manage.leyou.com

Access-Control-Allow-Credentials: true

Content-Type: text/html; charset=utf-8

Access-Control-Allow-Origin:可接受的域 ,是一个具体域名或者*(代表任意域名)

Access-Control-Allow-Credentials:是否允许携带cookie,默认情况下,cors不会携带cookie,除非这个值是true。

要想操作cookie,需要满足3个条件:

  • 服务的响应头中需要携带Access-Control-Allow-Credentials并且为true
  • 浏览器发起ajax需要指定withCredentials 为true
  • 响应头中的Access-Control-Allow-Origin一定不能为*,必须是指定的域名

2.2.复杂请求

预检请求(preflight):特殊请求会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求。

浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。

与简单请求相比,除了Origin以外,多了两个请求头:

Access-Control-Request-Method:接下来会用到的请求方式,比如PUT

Access-Control-Request-Headers:会额外用到的头信息

如果服务允许跨域,除了Access-Control-Allow-Origin和Access-Control-Allow-Credentials以外,这里又额外多出3个头:

Access-Control-Allow-Methods:允许访问的方式;

Access-Control-Allow-Headers:允许携带的头;

Access-Control-Max-Age:本次许可的有效时长,单位是秒,过期之前的ajax请求就无需再次进行预检了。

3.解决跨域

3.1 重新注入CorsFilter解决跨域

java 复制代码
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
 
/**
 * 跨域:指浏览器不允许当前页面所在的源去请求另一个源的数据。(要理解当前页面源是什么?)
 * 同源策略(SOP Same origin policy):是一种约定,由Netscape公司1995年引入浏览器,
 * 它是浏览器最核心也是最基本的安全功能,如果缺少同源策略,浏览器很容易受到XSS、CSFR
 * 等攻击。所谓同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个ip,也非同源。
 */
@Configuration
public class LeyouCorsConfiguration {
 
    @Bean
    public CorsFilter corsFilter() {
 
        // 初始化cros配置对象
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        // 允许跨域的域名,如果要携带cookie,不能写*。*:代表所有的域名都可以跨域访问
        // 可以添加多个域名(源:你页面所在的源)
        corsConfiguration.addAllowedOrigin("http://manage.leyou.com");
 
        // 允许携带cookie
        corsConfiguration.setAllowCredentials(true);
 
        // 允许跨域的请求方法,*代表所有方法。可以添加多个
        corsConfiguration.addAllowedMethod("*");
 
        // 允许跨域携带的头信息,*代表所有头。可以添加多个
        corsConfiguration.addAllowedHeader("*");
 
        // 本次许可的有效时间,单位秒,过期之前的ajax请求就无需再次进行预检啦
        // 默认是1800s,此处设置1h
        corsConfiguration.setMaxAge(3600L);
 
        // 初始化cors配置源对象
        UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
        // 拦截一切路径
        urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
 
        // 返回新的CorsFilter
        return new CorsFilter(urlBasedCorsConfigurationSource);
    }
}

3.2 实现 WebMvcConfigurer的addCorsMappings 的方法

注意注意注意:addMapping()配置应用路径(server.servlet.context-path)是不能进行拦截的,拦截的而是Controller配置确切的路径。一般配置/**即可,即拦截所有Controller配置的路径

java 复制代码
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) {
        // 拦截的路径
        // 注意注意注意:addMapping()配置应用路径(server.servlet.context-path)是不能进行拦            
        // 截的,拦截的而是Controller配置确切的路径
        // 一般配置/**即可,即拦截所有Controller配置的路径
        registry.addMapping("/**")
                // 允许跨域的域名,*:代表所有。允许携带cookie不能为*
                .allowedOrigins("*")
                // 允许跨域的请求方法
                .allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS")
                // 是否允许跨域携带cookie,为true允许跨域的域名需要指定,不能为*
                .allowCredentials(false)
                // 本次许可的有效时间,单位秒,过期之前的ajax请求就无需再次进行预检
                // 默认是1800s,此处设置1h
                .maxAge(3600)
                // 允许跨域携带的头信息,*代表所有头。可以添加多个
                .allowedHeaders("*");
    }
}

3.3 创建一个 filter 解决跨域

java 复制代码
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
 
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
 
@Component
@WebFilter(urlPatterns = { "/*" }, filterName = "headerFilter")
public class HeaderFilter implements Filter {
 
    private static final Logger logger = LoggerFactory.getLogger(HeaderFilter.class);
 
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
                         FilterChain filterChain) throws IOException, ServletException {
       HttpServletResponse httpServletResponse = (HttpServletResponse)servletResponse;
        // 解决跨域访问报错
        // 允许跨域的域名,*:代表所有域名
        httpServletResponse.setHeader("Access-Control-Allow-Origin", "*");
        // 允许跨域请求的方法
        httpServletResponse.setHeader("Access-Control-Allow-Methods",  "POST, PUT, GET, OPTIONS, DELETE");
        // 本次许可的有效时间,单位秒,过期之前的ajax请求就无需再次进行预检啦
        // 默认是1800s,此处设置1h
        httpServletResponse.setHeader("Access-Control-Max-Age", "3600");
        // 允许的响应头
        httpServletResponse.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, client_id, uuid, Authorization");
        // 支持HTTP 1.1.
        httpServletResponse.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
        // 支持HTTP 1.0. response.setHeader("Expires", "0");
        httpServletResponse.setHeader("Pragma", "no-cache");
        // 编码
        httpServletResponse.setCharacterEncoding("UTF-8");
        // 放行
        filterChain.doFilter(servletRequest, servletResponse);
    }
 
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        logger.info("-----------------cross origin filter start-------------------");
    }
 
    @Override
    public void destroy() {
        logger.info("-----------------cross origin filter end-------------------");
    }
}

3.4 @CrossOrigin注解

@CorssOrigin一个注解轻松解决,可以用在类上和方法。

参考文章:原文链接:https://blog.csdn.net/m0_48983233/article/details/122017773

相关推荐
华农第一蒟蒻15 小时前
谈谈跨域问题
java·后端·nginx·安全·okhttp·c5全栈
一直向钱2 天前
android 基于okhttp的socket封装
android·okhttp
linuxxx1102 天前
ajax回调钩子的使用简介
okhttp
一直向钱3 天前
android 基于okhttp 封装一个websocket管理模块,方便开发和使用
android·websocket·okhttp
linuxxx1104 天前
ajax() 回调函数参数详解
前端·ajax·okhttp
linuxxx1106 天前
ajax与jQuery是什么关系?
ajax·okhttp·jquery
耀耀_很无聊8 天前
12_OkHttp初体验
okhttp
heeheeai8 天前
okhttp使用指南
okhttp·kotlin·教程
啦工作呢10 天前
ES6 promise-try-catch-模块化开发
android·okhttp
杨杨杨大侠14 天前
手把手教你写 httpclient 框架(三)- 动态代理与请求处理机制
java·okhttp·github