Spring Boot 入门之路(8)--- 解决 Spring Boot 中的跨域问题

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/Geffin/article/details/100165247

在谈 Spring Boot 中的跨域问题之前,我想我们有必要先了解下同源策略

1 同源策略

不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源。该策略是浏览器安全的基石。

也许大家很疑惑,何为’'源“?何为“同源”?其实,源可以理解为协议,域名和端口号的组合,而同源指的是地址中的协议,域名和端口号均相同。

由于浏览器同源策略的影响,不是同源的脚本是不能操作其他源下面的对象的,非同源的网站之间不能发送 AJAX 请求。想要操作另一个源下的对象就需要跨域,其中跨域可以分为 JSONP 跨域和 CORS 跨域。

2 JSONP 跨域和 CORS 跨域

CORS,即 Cross-Origin Resource Sharing,中文意思为跨域资源共享。它定义了在跨域访问资源时浏览器和服务器之间如何进行通信。

CROS 是现在主流解决跨域问题的方案,它与 JSONP 之间的区别如下:

  1. JSONP 只能实现 GET 请求,而 CORS 支持所有类型的HTTP请求。
  2. 使用 CORS,开发者可以使用普通的 XMLHttpRequest 发起请求和获得数据,比起 JSONP 有更好的错误处理。
  3. JSONP 主要被老的浏览器支持,它们往往不支持 CORS ,而绝大多数现代浏览器都已经支持了 CORS。

总的来说,CORS 与 JSONP 相比,更为先进,方便和可靠。

3 CORS 跨域简介

CORS 将请求分为两类:简单请求和非简单请求。

简单请求

下面是一个简单的例子:

GET /test HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate, sdch, br
Origin: http://www.examples.com
Host: www.examples.com

对于简单请求,CORS 的策略是请求时在请求头中增加一个 Origin 字段,服务器收到请求后,根据该字段判断是否允许该请求访问。若允许,则在 HTTP 头信息中添加 Access-Control-Allow-Origin 字段,并返回正确的结果,否则不会在 HTTP 头信息中添加 Access-Control-Allow-Origin 字段。

非简单请求

对于非简单请求的跨源请求,浏览器会在真实请求发出前,增加一次 OPTION 请求,称为预检请求。预检请求将真实请求的信息,包括请求方法、自定义头字段、源信息添加到 HTTP 头信息字段中,询问服务器是否允许这样的操作。例子如下:

扫描二维码关注公众号,回复: 7644051 查看本文章
OPTIONS /test HTTP/1.1
Origin: http://www.examples.com
Access-Control-Request-Method: DELETE
Access-Control-Request-Headers: X-Custom-Header
Host: www.examples.com

服务器收到请求时,需要分别对 Origin、Access-Control-Request-Method(请求使用的 HTTP 方法)、Access-Control-Request-Headers(请求中包含的自定义头字段) 进行验证,验证通过后,会在返回 HTTP头信息中添加 :

Access-Control-Allow-Origin: http://www.examples.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: X-Custom-Header
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 1728000

其含义为:

  1. Access-Control-Allow-Methods: 真实请求允许的方法
  2. Access-Control-Allow-Headers: 服务器允许使用的字段
  3. Access-Control-Allow-Credentials: 是否允许用户发送、处理 cookie
  4. Access-Control-Max-Age: 预检请求的有效期,单位为秒。有效期内,不会重复发送预检请求

当预检请求通过后,浏览器会发送真实请求到服务器。这就实现了跨源请求。

4 模拟跨域请求

我们先不使用 CORS,看看接下来会发生什么?

我们建立两个 Spring Boot ,分别命名为 test 和 demo。

test 项目的控制器:

package edu.szu.test.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class IndexController {

	@RequestMapping("index")
    public String index(){
        return "index" ;
	}
}

application.properties:

# 页面默认前缀目录
spring.mvc.view.prefix=/WEB-INF/jsp/
# 响应页面默认后缀
spring.mvc.view.suffix=.jsp
# 指定端口
server.port=8080

test/src/main/webapp/WEB-INF/jsp/index.jsp:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
Hello 8080!
</body>
</html>

demo 项目的控制器:

package com.example.demo.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class IndexController {

	@RequestMapping("/index")
    public String index(){
        return "index" ;
	}
}

application.properties:

# 页面默认前缀目录
spring.mvc.view.prefix=/WEB-INF/jsp/
# 响应页面默认后缀
spring.mvc.view.suffix=.jsp
# 指定端口
server.port=8087

demo/src/main/webapp/WEB-INF/jsp/index.jsp:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="http://code.jquery.com/jquery-latest.js"></script>
</head>
<body>
Hello 8087!
<input type="button" value="commit" onclick="test()"/>
</body>
<script type="text/javascript">
    function test(){
        $.ajax({
            url:'http://localhost:8080/index',
            type:'post',
            dataType:'text',
            success:function(data){
                console.log(data);
            }
        });
    }
</script>
</html>

运行 test 和 demo 两个项目的启动类,在浏览器中输入 http://localhost:8087/index,发现页面一直无法跳转。打开控制台,发现如下报错。

在这里插入图片描述
翻译一下,由于在请求的资源上没有 Access-Control-Allow-Origin 的头部 header,8087这个域没有访问权限,XMLHttpRequest 不能加载8080端口的数据。

5 Spring Boot 配置 CORS 的方法

通过 @CrossOrigin 实现

在方法或类上添加 @CrossOrigin 注解,可以直接配置 CORS。

@Controller
public class IndexController {

	@RequestMapping("index")
	@CrossOrigin("http://localhost:8087")
    public String index(){
        return "index" ;
	}
}

配置过滤器

@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {

    @Bean
    public CorsFilter corsFilter() {
        final UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
        final CorsConfiguration corsConfiguration = new CorsConfiguration();
        //是否允许请求带有验证信息
        corsConfiguration.setAllowCredentials(true);
        //允许访问的客户端域名
        corsConfiguration.addAllowedOrigin("*");
        //允许服务端访问的客户端请求头
        corsConfiguration.addAllowedHeader("*");
        //允许访问的方法名,GET POST等
        corsConfiguration.addAllowedMethod("*");
        urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
        return new CorsFilter(urlBasedCorsConfigurationSource);
    }
}

该方式针对全局配置有效。

配置拦截器

@Configuration
public class MyConfiguration implements WebMvcConfigurer  {

    @Override  
    public void addCorsMappings(CorsRegistry registry) {  
        registry.addMapping("/**")  
                .allowCredentials(true)  
                .allowedHeaders("*")  
                .allowedOrigins("*")  
                .allowedMethods("*");  

    }  
}

该方式针对全局配置有效。

参考:SpringBoot配置Cors解决跨域请求问题
CORS解决ajax跨域问题
Spring Boot 2.0 解决跨域问题 SpringBoot2.X
(十三) : SpringBoot设置支持跨域请求

猜你喜欢

转载自blog.csdn.net/Geffin/article/details/100165247