Halo(九)

跨域问题

域名A(http://www.a.com)的 Web 应用程序中,
通过标签引入了域名B(http://ww.b.com)站点的某图片资源(http://www.b.com/image.jpg),
域名A的 Web 应用就会导致浏览器发起一个跨域 HTTP 请求。


同源策略:
    不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源。
    一个请求地址里面的协议、域名和端口号都相同,就属于同源。


不允许跨域访问的网站无法跨域访问(由于同源策略)。

CORS(Cross-Origin Resource Sharing)解决跨域请求问题

CORS基本思想:
    使用自定义的HTTP请求头使浏览器和服务器相互了解对方,从而决定请求或响应成功与否。


CORS分为简单请求和非简单请求(需预检请求)两类:

    简单请求

        请求方式使用下列方法之一:
            GET
            HEAD
            POST
 
        HTTP的头信息不超出以下几种字段 
            1. Accept
            2. Accept-Language
            3. Content-Language
            4. Last-Event-ID
            5. Content-Type 的值仅限于下列三者之一:
                text/plain
                multipart/form-data
                application/x-www-form-urlencoded

        对于简单请求,浏览器会直接发送CORS请求
            请求头字段header中加入:origin
            响应头字段header中加入:
                Access-Control-Allow-Origin:可跨域的源
                Access-Control-Allow-Credentials:是否允许用户发送、处理 cookie(可选)

    非简单请求(除了简单请求,其他都是非简单请求)

        使用了下面任一 HTTP 方法:
            PUT
            DELETE
            CONNECT
            OPTIONS
            TRACE
            PATCH
 
        Content-Type 的值不属于下列之一:
            application/x-www-form-urlencoded
            multipart/form-data
            text/plain

        浏览器会先发送预检请求(不会携带Cookie和传递的参数),发送一次Preflight Request,接收一个Preflight Response。
        预检请求判断是否允许跨域访问后,才决定是否发送真正的请求。

        非简单请求会在头部多返回以下字:
            请求头:origin
            响应头:
                Access-Control-Allow-Origin:可跨域的资源路径
                Access-Control-Allow-Methods:服务端支持的请求方法
                Access-Control-Allow-Headers:服务器允许使用的字段
                Access-Control-Allow-Credentials:是否允许用户发送、处理 cookie
                Access-Control-Max-Age:预检请求的有效期,单位为秒。有效期内,不会重复发送预检请求

Spring Boot CORS 实现

局部:
    Controller类上使用(对该类所有方法有效):@CrossOrigin
    Controller方法上使用:@CrossOrigin


全局:
    使用配置类实现

方法1. 添加一个配置类

@Configuration
public class CorsConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")  //允许跨域访问的路径
                .allowedOrigins("*")    //允许跨域访问的资源路径
                .allowedMethods("POST", "GET", "PUT", "OPTIONS", "DELETE")  //允许请求方法
                .allowedHeaders("Content-Type", "ADMIN-Authorization")  //
                .maxAge(3600)   //预检间隔时间
                .allowCredentials(true);    //是否允许发送cookie
    }
}

方法2. 添加一个过滤器

public class CorsFilter extends GenericFilterBean {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;

        /** 设置自定义头 */
        httpServletResponse.setHeader("Access-Control-Allow-Origin", httpServletRequest.getHeader(HttpHeaders.ORIGIN));
        httpServletResponse.setHeader("Access-Control-Allow-Headers", "Content-Type, ADMIN-Authorization");
        httpServletResponse.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
        httpServletResponse.setHeader("Access-Control-Allow-Credentials", "true");
        httpServletResponse.setHeader("Access-Control-Max-Age", "3600");

        //非预检请求,给予通过(预检请求直接返回响应头)
        if (!CorsUtils.isPreFlightRequest(httpServletRequest)) {
            chain.doFilter(httpServletRequest, httpServletResponse);
        }
    }
}

@Configuration
public class HaloConfiguration {
    @Bean
    public FilterRegistrationBean corsFilter() {
        FilterRegistrationBean corsFilter = new FilterRegistrationBean<>();
        //设置优先级
        corsFilter.setOrder(Ordered.HIGHEST_PRECEDENCE);
        corsFilter.setFilter(new CorsFilter());
        corsFilter.addUrlPatterns("/api/*");
        return corsFilter;
    }
}

你可能感兴趣的:(Halo(九))