前端 | 跨域问题的前后端解决方案


01 什么是跨域问题

跨域问题是指在前端和后端开发中,当浏览器发起跨域请求时会受到同源策略的限制而导致请求失败的情况。同源策略是一种安全机制,它限制了浏览器在不同域名、不同端口或不同协议之间进行跨域的资源访问。

同源策略要求请求的域名、端口和协议必须完全一致,只有当它们完全相同时,浏览器才允许进行跨域请求。否则,浏览器会拒绝响应跨域请求,以防止恶意网站获取用户的敏感信息或进行恶意操作。

02 跨域问题出现的示例

例如:前端服务的访问路径是http://localhost:8070,后端服务的访问路径是http://localhost:8080,当前端页面需要向后端服务发送请求时,就会报跨域错误。

下面是代码示例:

  • 前端(express)
    • main.js

      import express from 'express'			// 导入前端服务器
      const app = express()					// 创建前端服务器对象
      app.use(express.static("./static"))		// 所有请求发向前端服务器的静态资源
      app.listen(8070)						// 8070端口作为请求端口
      
    • demo.html

      <body>
      ...
      <!--js部分-->
      <script>
          fetch("http://localhost:8080/api/students") // 这里会出现跨域问题
              .then(resp => resp.json())
              .then(data => {
                
                ...})
      </script>
      </body>
      
  • 后端(SpringBoot)
    • Student.java

      // 省略 构造方法 getter setter
      public class Student {
              
              
          private int id;
          private String name;
          private String sex;
          private int age;
      }
      
    • TestController.java

      // 浏览器访问http://localhost:8080/api/students
      @RestController()
      @RequestMapping("api")
      public class TestController {
              
              
          @GetMapping("/students")
          public ResponseEntity<ArrayList<Student>> getStudents() {
              
              
              Student s1 = new Student(1, "张三", "男", 18);// s2 s3 s4 略
              ArrayList<Student> students = new ArrayList<>(List.of(new Student[]{
              
              s1, s2, s3, s4}));
              return ResponseEntity.ok(students);
          }
      }
      

03 后端解决方案

后端可以使用@CrossOrigin注解,指定哪些域可以访问,默认配置是所有域都可访问。
在Controller类上或对应的接口方法上加该注解即可:

  • TestController.java
    @RestController()
    @RequestMapping("api")
    @CrossOrigin("http://localhost:8070") // 可以不写括号和参数 默认表示允许所有域
    public class TestController {
          
          
    
    	@GetMapping("/students")
    	// 或者加在这里 仅对某接口生效
    	public ResponseEntity<ArrayList<Student>> getStudents() {
          
          
    		Student s1 = new Student(1, "张三", "男", 18);// s2 s3 s4 略
    		ArrayList<Student> students = new ArrayList<>(List.of(new Student[]{
          
          s1, s2, s3, s4}));
    		return ResponseEntity.ok(students);
    	}
    	
    }
    

只改后端即可,前端代码不变。

04 前端解决方案

前端解决方案是使用代理。只需要改前端代码,后端不需要使用@CrossOrigin注解,后端代码不变。
(个人推荐使用前端解决方案)

  • npm安装插件

    # 命令行安装必要的库
    npm install http-proxy-middleware --save-dev
    
  • main.js
    在原有的代码中,添加一个import和一个app.use()。

    import express from 'express'
    // [新增] 导入中间件
    import {
          
          createProxyMiddleware} from "http-proxy-middleware"
    const app = express()
    // [新增] 设置路径中以/api开头的请求进行跨域代理
    app.use("/api", createProxyMiddleware({
          
          target: "http://localhost:8080", changeOrigin: true}))
    app.use(express.static("./static")) // 其他请求走之前默认的配置
    app.listen(8070)
    
  • demo.html
    html页面修改发送请求的部分

    <body>
    ...
    <!--js部分-->
    <script>
        fetch("/api/students") // 因为是代理 所以请求是发向前端服务器的代理中间件 直接写uri路径即可
            .then(resp => resp.json())
            .then(data => {
            
            ...})
    </script>
    </body>
    

扩展阅读:关于@CrossOrigin注解

(来自ChatGPT)

在Java中,@CrossOrigin注解用于处理跨域请求。它是Spring框架提供的注解之一,用于在控制器类或处理方法上启用跨域请求支持。

使用@CrossOrigin注解可以配置允许跨域请求的规则,包括允许的域名、方法、请求头等。以下是@CrossOrigin注解的常用属性:

  • value:指定允许跨域请求的源,可以是单个字符串或字符串数组。例如,value = "http://example.com"value = {"http://example.com", "http://another-domain.com"}
  • origins:与value属性作用相同,用于指定允许跨域请求的源。
  • methods:指定允许的HTTP请求方法,可以是单个字符串或字符串数组。默认情况下,允许所有方法(GET、POST等)。例如,methods = RequestMethod.GETmethods = {RequestMethod.GET, RequestMethod.POST}
  • allowedHeaders:指定允许的请求头信息,可以是单个字符串或字符串数组。默认情况下,允许所有头信息。例如,allowedHeaders = "Authorization"allowedHeaders = {"Authorization", "Content-Type"}
  • exposedHeaders:指定允许暴露给客户端的响应头信息,可以是单个字符串或字符串数组。
  • allowCredentials:指定是否允许发送身份验证凭据(如cookies)到跨域请求的服务器。默认情况下是false,表示不允许发送凭据。
  • maxAge:指定预检请求的最大缓存时间,以秒为单位。预检请求是一种用于验证跨域请求是否安全的请求。

以下是一个使用@CrossOrigin注解的示例:

@RestController
@CrossOrigin(origins = "http://example.com", methods = RequestMethod.GET, allowedHeaders = "Authorization")
public class MyController {
    
    
  
  @GetMapping("/data")
  public ResponseEntity<String> getData() {
    
    
    // 处理请求并返回响应
  }
  
  // 其他处理方法...
}

在上述示例中,@CrossOrigin注解应用于MyController控制器类上,指定了允许跨域请求的源为"http://example.com",允许的方法为GET,允许的请求头为Authorization。这样,只有来自"http://example.com"的GET请求,并且包含Authorization请求头的请求才能跨域访问/data接口。

使用@CrossOrigin注解可以方便地处理跨域请求,但需要注意跨域请求可能带来的安全风险,因此在配置允许跨域请求时应谨慎考虑。

猜你喜欢

转载自blog.csdn.net/xuzhongyi103/article/details/131614821