23

spring boot 中通过CORS实现跨域

 4 years ago
source link: https://www.tuicool.com/articles/jEnAFr3
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

一、跨域问题出现的原因

出现跨域问题的原因是同源策略。

同源策略

主要是三同:同协议、同域名、同端口,

同源策略目的

  • 保证用户信息安全,防止恶意网站窃取数据。同源策略是必须的,否则cookie可以共享。

同源策略的限制范围

  • cookie、localstorage、indexdb无法读取。
  • DOM无法获取。
  • ajax请求不能发送。

规避策略

  1. cookie:设置 document.domain 共享cookie。
  2. DOM获取:(父子页面通信)H5引入了一个API,这个API为windows对象新增了一个 window.postMessage 方法,允许跨窗口通信,无论这两个窗口是否同源。
  3. window.opener.postMessage(content,origin)
    
    content是消息的具体内容,origin是协议 + 域名 + 端口
    
  1. AJAX:
  • JSONP:JSONP是服务器无客户端跨源通信的常用方法。基本思想是网页通过添加一个 <script> 元素,向服务器请求json数据,这种做法不受同源政策的限制,服务器收到请求后,将数据放在一个指定名字的回调函数里面传回来。(只能发GET请求)
  • WebSocket: WebSocket 是一种通信协议。使用 ws:// (非加密)和 wss:// (加密)作为协议前缀。该协议不实行同源政策,只要服务器支持,就可以通过它进行跨源通信。
  • CORS:详解如下。

跨域资源共享(corss-origin resource sharing):CORS需要浏览器和服务器同时支持。目前所有浏览器都支持该功能,IE浏览器不能低于IE10。整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。

两种请求

  • 浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。

CORS请求

1. 简单请求

  • 对于简单请求,浏览器直接发出CORS请求。具体来说,就是 在Header中增加一个 Origin 字段 。如果浏览器发现跨源AJAX请求是简单请求,就自动在头信息之中,添加一个 Origin 字段。
GET /cors HTTP/1.1      
Origin: http://localhost:8081     //浏览器添加字段,说明本次请求来自哪个源(协议+域名+端口)。
Host: 119.23.214.114
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...

  • 如果 Origin 指定的源在不在后端的许可白名单范围内,服务器会返回一个正常的http回应。浏览器接收后发现,这个 response 的Header没有包含 Access-Control-Allow-Origin 字段,就知道出错了,从而抛出一个错误,被 XMLHttpRequestonerror 回调函数捕获。 这种错误无法通过状态码识别,因此HTTP response的状态码有可能是200。

2. 非简单请求

  • 非简单请求是那种对服务器有特殊要求的请求,比如请求方法是 PUTDELETE ,或者 Content-Type 字段的类型是 application/json
  • 非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求(preflight)。浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的 XMLHttpRequest 请求,否则就报错。
以上内容链接: https://www.jianshu.com/p/413a2f11828d

二、spring boot 通过CORS解决跨域问题

先创建一个项目server作为服务器端,默认端口为8080,并在服务端提供两个接口:

//方便client分别发送不同类型请求的时候可以 观察一下简单请求和非简单请求的区别
@RestController
public class HelloController {
    @GetMapping("gethello") //get 类型public String getHello(){
        return "get hello";
    }
    @PutMapping("puthello") //put类型
    public String putHello(){
        return "put hello";
    }
}

再创建一个项目client作为请求端,并设置请求端的端口为8081:

server.port=8081

在请求端的resources/static目录下增加本次访问所需要的页面index.html,记得同时自己找一个jquery.min.js 也放到static目录下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="jquery.min.js"></script>
</head>
<body>
<div id="div"></div>
<input type="button" value="获取" onclick="gethello()"> //用于测试简单请求
<input type="button" value="更新" onclick="puthello()"> //用户测试非简单请求
<script>
    function gethello() {
        $.get('http://localhost:8080/gethello',function (msg) {
            $("#div").html(msg); //将调用接口返回值在页面上显示
        });
    }
    function puthello() {
       $.ajax({
           type:'put',
           url:'http://localhost:8080/puthello',
           success:function (msg) {
               $("#div").html(msg);
           }
       })
    }
</script>
</body>
</html><!DOCTYPE html>

接下来看看跨域失败的的时候:首先启动server端,再启动client端。在浏览器中访问:http://localhost:8081/index.html,点击获取按钮:

7NRzyea.png!web

然后我们在服务端中通过CORS解决跨域的问题,有两种解决办法。

1.在接口类或者方法上面添加 @CrossOrigin注解

   @GetMapping("gethello")
    @CrossOrigin(value = "http://localhost:8081") //指定可以访问的白名单
    public String getHello(){
        return "get hello";
    }

2.实现WebMvcConfigurer接口重写addCorsMappings方法


@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
       registry.addMapping("/**").allowedOrigins("http://localhost:8081")
                .allowedMethods("*")
                .allowedHeaders("*")
          .maxAge(30000);
} }

解决了跨域问题后,重启服务端:再进行获取和更新操作:

1.获取操作 成功

uQVJzaa.png!web

2.更新操作

7FrmmuZ.png!web

UjiMZjV.png!web

正如前面所说的非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求(preflight)。浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的 XMLHttpRequest 请求,否则就报错。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK