51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

【WEB 系列】SpringBoot 跨域及后端解决方案

什么是跨域? {#什么是跨域?}

  • 一个网页向另一个不同域名 / 不同协议 / 不同端口的网页请求资源,这就是跨域。
  • 跨域原因产生:在当前域名请求网站中,默认不允许通过 ajax 请求发送其他域名。

CROS 常见 header {#CROS 常见 header}

Access-Control-Allow-Origin:http://somehost.com 表示允许[http://somehost.com 发起跨域请求](http://somehost.com 发起跨域请求 /)。

Access-Control-Max-Age:86400 表示在 86400 秒内不需要再发送预校验请求。

Access-Control-Allow-Methods: GET,POST,PUT,DELETE 表示允许跨域请求的方法。

Access-Control-Allow-Headers: content-type 表示允许跨域请求包含 content-type

模拟跨域 {#模拟跨域}

后台代码 {#后台代码}

新建一个 SpringBoot 项目,添加如下依赖,版本随意,我自己是 2.5.2 版本

  • pom.xml 文件
<!-- springboot 版本,2.5.2 -->
<parent>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-parent</artifactId>
   <version>2.5.2</version>
   <relativePath/> <!-- lookup parent from repository -->
</parent>
<!-- 添加 web -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 添加 lombok 简化实体类 -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>
  • 创建一个实体类
/**
 * Software:IntelliJ IDEA 2021.1.1 x64
 * Author: https://www.mobaijun.com
 * Date: 2021/7/6 16:16
 * ClassName:GoodsDo
 * 类描述: 商品实体类
 */
@Data
public class GoodsDo {
    /**
     * 商品 id
     */
    private Long id;
    /**
     * 商品名称
     */
    private String name;
    /**
     * 商品价格
     */
    private String price;
    /**
     * 商品图片
     */
    private String pic;
}
  • 服务层接口
import com.mobai.pojo.GoodsDo;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;


/**

`
`
* Software:IntelliJ IDEA 2021.1.1 x64


* Author: https://www.mobaijun.com


* Date: 2021/7/6 16:17


* ClassName:GoodsService



* `类描述:商品实现类
  `/
  @Service
  public class GoodsService {
  /`*
  ``
  `
  * `获取商品列表
    */``
    `public` `List<GoodsDo>` `getGoodsList()` `{`
    `// 模拟从数据库查询出的结果返回`
    `List<GoodsDo>` goodsList `=` `new` `ArrayList<GoodsDo>();`
    `GoodsDo` goods `=` `new` `GoodsDo();`
    goods`.setId(1L);`
    goods`.setName("苹果");`
    goods`.setPic("apple.jpg");`
    goods`.setPrice("3.5");`
    goodsList`.add(`goods`);`
    `return` goodsList`;`
    `}`
    `}

  • 控制器接口
import com.mobai.pojo.GoodsDo;
import com.mobai.service.GoodsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;


/**

`
`
* 
  Software:IntelliJ IDEA 2021.1.1 x64





* 
  Author: https://www.mobaijun.com





* 
  Date: 2021/7/6 16:17





* 
  ClassName:GoodsController






* `
  `类描述:
  */
  @RestController
  public class GoodsController {
  `
  `

  @Autowired
  private GoodsService goodsService;
  `
  `

  /**
  `
  ``
  `
  * 遵循 Restful 规范的接口


  * `请求地址:http://127.0.0.1:8080/goods
    */``
    `@GetMapping("/goods")`
    `public` `List<GoodsDo>` `getList()` `{`
    `return` goodsService`.getGoodsList();`
    `}`
    `}

前端代码 {#前端代码}

新建一个文件夹,创建 goods.html 文件,编写如下请求代码:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>商品请求测试</title>
    <!-- Bootstrap 核心 CSS 文件 -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css"
          integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
<script>
    // 初始化方法
    $(function () {
        var row = "";
        $.ajax({
            type: "GET",
            // 后端接口地址
            url: "http://127.0.0.1:8080/goods",
            dataType: "json",
            contentType: "application/json; charset=utf-8",
            success: function (res) {
                $.each(res, function (i, v) {
                    row = "<tr>";
                    row += "<td>" + v.id + "</td>";
                    row += "<td>" + v.name + "</td>";
                    row += "<td>" + v.price + "</td>";
                    row += "<td>" + v.pic + "</td>";
                    row += "</tr>";
                    $("#goodsTable").append(row);
                });
            },
            error: function (err) {
                console.log(err);
            }
        });
    });
</script>
</body>
</html>

如果在 idea 或者 webStorm 中可以直接点击右上角浏览器运行,会自动生成一个服务器和端口,打开浏览器控制台页面,查看请求信息:

模拟跨域

has been blocked by CORS policy ,意味着被 CORS 策略阻塞了。我们的前端页面请求被 CORS 阻塞了,所以没成功获取到后端接口返回的数据。

CORS 跨域介绍 {#CORS- 跨域介绍}

跨域实际上源自浏览器的同源策略,所谓同源,指的是协议、域名、端口都相同的源 (域)。浏览器会阻止一个域的 JavaScript 脚本向另一个不同的域发出的请求,这也是为了保护浏览器的安全。

在上面的例子中,发起请求的网页与请求资源的 URL 协议、域名、端口均不同,所以该请求就被浏览器阻止了。

CORS 的意思就是 跨域资源共享,是一种允许跨域 HTTP 请求的机制,在这种情况下我们就要想办法实现 CORS 跨域了。

SpringBoot 的 Cors 跨域设置 {#SpringBoot 的 Cors 跨域设置}

  • SpringBoot 可以基于 Cors 解决跨域问题,Cors 是一种机制,告诉我们的后台,哪边(origin )来的请求可以访问服务器的数据。
  • 全局配置类
  • 配置实例如下:
package com.mobai.config;

import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;


/**

`
`
* 
  Software:IntelliJ IDEA 2021.1.1 x64





* 
  Author: https://www.mobaijun.com





* 
  Date: 2021/7/7 10:55





* 
  ClassName:CorsConfig






* `
  `类描述: cors 配置类
  */
  // @Configuration
  public class CorsConfig {
  `
  `

  @Bean`
  `public` `WebMvcConfigurer` `corsConfigurer()` `{`
  `return` `new` `WebMvcConfigurer()` `{`
  `// 重写父类提供的跨域请求处理的接口`
  `@Override`
  `public` `void` `addCorsMappings(CorsRegistry` registry`)` `{`
  `// 添加映射路径`
  registry`.addMapping("/**")`
  `// 放行哪些原始域`
  `.allowedOriginPatterns("")
  // 是否发送 Cookie 信息
  .allowCredentials(true)
  // 放行哪些原始域(请求方式)
  .allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS", "PATCH")
  // 放行哪些原始域(头部信息)
  .allowedHeaders("`"`)`
  `// 暴露哪些头部信息(因为跨域访问默认不能获取全部头部信息)`
  `.exposedHeaders("Header1",` `"Header2")`
  `// 预请求的结果有效期,默认 1800 分钟,3600 是一小时`
  `.maxAge(3600);`
  `}`
  `};`
  `}`
  `}


通过上面的配置类,实现了允许所有对该 Spring Boot 的请求跨域。此时再次打开网页,被跨域策略阻塞的提示消失,界面显示如下:

成功界面

小插曲 {#小插曲}

如果你的 springboot 版本较低,在 2.2 以下 ,具体那个版本我没有试过,跨域配置需要将 .allowedOriginPatterns 替换成 .allowedOrigins , 因为在新版本 SpringBoot 中,跨域配置将 .allowedOrigins 替换成 .allowedOriginPatterns

参考文章:

  1. (5 条消息) When allowCredentials is true, allowedOrigins cannot contain the special value "*" since that cannot_想望着太阳的博客 -CSDN 博客
  2. 浅谈 SpringBoot 的 Cors 跨域设置 - 云扬四海
  3. Spring Boot 跨域与前后端分离丨慕课网教程
赞(0)
未经允许不得转载:工具盒子 » 【WEB 系列】SpringBoot 跨域及后端解决方案