JSONP 太 low,Spring Boot实现CORS跨域

一、跨域相关概念简介

1、同源策略[same origin policy]:

它是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源, 同源策略是浏览器安全的基石。同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。

这里为了方便大伙清晰地理解同源策略的概念,截取百度百科的简介:

  • 同源策略,它是由Netscape提出的一个著名的安全策略
  • 现在所有支持JavaScript 的浏览器都会使用这个策略。
  • 所谓同源是指,域名,协议,端口均相同。
  • 当一个浏览器的两个tab页中分别打开来 百度和谷歌的页面
  • 当浏览器的百度tab页执行一个脚本的时候会检查这个脚本是属于哪个页面的,即检查是否同源,只有和百度同源的脚本才会被执行。
  • 如果非同源,那么在请求数据时,浏览器会在控制台中报一个异常,提示拒绝访问。
  • 同源策略是浏览器的行为,是为了保护本地数据不被JavaScript代码获取回来的数据污染,因此拦截的是客户端发出的请求回来的数据接收,即请求发送了,服务器响应了,但是无法被浏览器接收。

2、JSONP:

我们在实际开发时,或多或少也会经常遇到跨域的需求,而传统的跨域方案一般采用JSONP,但是JSONP只支持get请求,不支持post、put、delete等其他请求,有局限性,并且现在提供 RESTful 风格的API,除了 get 请求,put、post、delete也会经常使用,而 JSONP 只支持 get请求,这在 RESTful 应用中就略显吃力了。

3、CORS:

因此,我们这里引进一个CORS(跨域资源共享)的概念:CORS,全称Cross-Origin Resource Sharing  ,它是一种允许当前域(domain)的资源(比如html/js/web service)被其他域(domain)的脚本请求访问的机制,通常由于同域安全策略(the same-origin security policy)浏览器会禁止这种跨域请求。

CORS是一个W3C标准,是一份浏览器技术的规范,提供了web服务从不同网域传来沙盒脚本的方法,它允许浏览器向跨域服务器发送Ajax请求,打破了Ajax只能访问本站内的资源限制,从而避开浏览器的同源策略,这是JSONP模式的现代版。

在传统的Spring框架中,有提供了CORS的解决方案,这里只介绍SpringBoot中实现CORS跨域的配置方案。

二、SpringBoot实现CORS示例

1、搭建SpringBoot应用

使用开发工具IDEA或Eclipse等,分别新建两个SpringBoot项目:

  • 应用一名称:springboot-cors1
  • 应用二名称:springboot-cors2

我使用的是2.1.7.RELEASE版本 ,添加相关依赖即可:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

2、配置应用端口

两个应用,分别在application.properties中配置不同的端口:

  • server.port=8081

  • server.port=8082

3、提供HTTP接口方法

在springboot-cors1 应用 新增一个控制器类,并提供一个get请求方法:

@RestController
public class IndexController {

    @GetMapping("/test")
    public String corsTest(){
        return "hello,CORS !";
    }

}

4、新增测试

在 springboot-cors2 新增一个index.html ,提供一个按钮,发送get请求跳转访问 应用一 springboot-cors1 

分别启动两个应用,访问 localhost:8082 ,点击get按钮,从而8082跨域请求8081接口,由于同源安全策略,请求被限制,打开浏览器调试模式,看到控制台报错如下:

5、添加CORS配置

5.1 对单个接口方法配置CORS

在springboot-cors1 的IndexController中corsTest()方法上增加注解,允许来自http://localhost/8082的应用请求该接口方法,如下:

重启springboot-cors1,再次访问应用二: localhost:8082 ,点击get按钮,这次便会成功跨域请求到应用一的接口内容:

点进 CrossOrigin 注解,可以看到该注解也可以放在类上,即应用于该类下的所有接口方法,都允许被跨域请求配置中的URL

5.2 对某个Controller下的所有接口方法配置CORS

配置在类上,就不用每个接口方法都设置:

但是,这样还是不够方便,假如我有很多接口需要允许跨域请求,岂不是每个controller类上都要配置该注解。

5.3 配置全局的CORS

方法(1)添加配置类:

package com.stwen.cors.config;

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;

/**
 * @description: cors过滤器配置
 * @author: stwen_gan
 * @date: 2019/08/08
 **/
@Configuration
public class CorsFilterConfig {
    @Bean
    public CorsFilter corsFilter() {
        final UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
        final CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.setAllowCredentials(true);
        //若要允许被所有网域请求,可以配置*
        corsConfiguration.addAllowedOrigin("http://localhost:8082");
        corsConfiguration.addAllowedHeader("*");
        //允许跨域请求的方法类型:GET、POST、PUT、DELETE 等
        corsConfiguration.addAllowedMethod("*");
        urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
        return new CorsFilter(urlBasedCorsConfigurationSource);
    }

}

方法(2)添加配置类:

新建一个WebMvcConfig配置类 ,继承WebMvcConfigurerAdapter (SpringBoot 1.x 版本),并重写addCorsMappings方法。

package com.stwen.cors.config;

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

/**
 * @description:
 * @author: stwen_gan
 * @date: 2019/08/08
 **/
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                //允许跨域请求的方法类型:GET、POST、PUT、DELETE 等
                .allowedMethods("*")
                //若要允许被所有网域请求,可以配置*
                .allowedOrigins("http://localhost:8082")
                .allowedHeaders("*");
        super.addCorsMappings(registry);
    }
}

【推荐】如果是 Springboot2.0 以上,已经抛弃WebMvcConfigurerAdapter ,建议使用WebMvcConfigurationSupport,如下:

package com.stwen.cors.config;

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

/**
 * @description:
 * @author: stwen_gan
 * @date: 2019/08/08
 **/
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                //若要允许被所有网域请求,可以配置*
                .allowedOrigins("http://localhost:8082")
                .allowedMethods("POST", "GET", "PUT", "OPTIONS", "DELETE")
                //预检请求--最大时间
                .maxAge(3600)
                .allowedHeaders("*");
        super.addCorsMappings(registry);
    }

}

配置的详细信息说明如下:

  • addMapping:配置可以被跨域的路径,可以任意配置,可以具体到直接请求路径。
  • allowedMethods:允许什么请求方法类型,可以访问该跨域资源服务器,如:POST、GET、PUT、DELETE等。
  • allowedOrigins:允许什么请求域名访问我们的跨域资源,可以固定单条或者多条内容,如:“http://localhost:8082”,只有该域名可以访问我们的跨域资源。若要允许被所有网域请求,可以配置* 。
  • allowedHeaders:允许什么的请求header访问,可以自定义设置任意请求头信息。
  • maxAge:预检请求--最大时间。

方法(3)使用Filter方法:

需要在启动类加上@ServletComponentScan注解

@WebFilter(urlPatterns = "*")
public class CorsFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest)request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        httpResponse.setCharacterEncoding("UTF-8");
        httpResponse.setContentType("application/json; charset=utf-8");
        httpResponse.setHeader("Access-Control-Allow-Origin", "*");
        httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
        httpResponse.setHeader("Access-Control-Allow-Methods", "*");
        httpResponse.setHeader("Access-Control-Allow-Headers", "Content-Type,Authorization");
        httpResponse.setHeader("Access-Control-Expose-Headers", "*");
        filterChain.doFilter(httpRequest, httpResponse);
    }

    @Override
    public void destroy() {

    }
}

6、PUT跨域请求

CORS也有一些限制,两种模型可以实现:

(1)简单模型

支持get/post/put/delete请求,例如返回Access-Control-Allow-Origin:*,但是不允许自定义header且会忽略cookies,且post数据格式有限制,只支持‘text/plain','application/x-www-urlencoded'and'multipart/form-data',其中’text/plain'默认支持,后面两种需要下面的预检请求和服务器协商。

(2)协商模型/预检请求(Preflighted Request)

举例:浏览器发出PUT请求,OPTION请求返回Access-Control-Allow-Origin:*,Access-Control-Allow-Methods:’PUT’,服务器同意所有域的PUT请求,浏览器收到并继续发出真正的PUT请求,服务器响应并再次返回Access-Control-Allow-Origin:*,允许浏览器的脚本执行服务器返回的数据。

在springboot-cors2 的index.html 增加一个put请求按钮:

在springboot-cors1 增加put接口方法:

分别启动两个应用,测试访问:localhost:8082

第一次跨域请求时,会先预检,先看第一个test2,预检请求是否支持,在maxAge 时间内,不用再次发起预检:

第二个,真正发起请求,获取响应

需要源码的,请下方评论,看到会发你。

本文来自:CSDN  作者:stwen_gan  https://blog.csdn.net/a1036645146/article/details/98843846

转载请注明出处,谢谢。

参考:

https://mp.weixin.qq.com/s/GcMuJ23WVvo2s_6LSgR4fA

https://blog.csdn.net/lizc_lizc/article/details/81155895

https://blog.csdn.net/yft_android/article/details/80307672

https://baike.baidu.com/item/CORS/16411212

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值