vue工具之解决跨域问题

一、概述

1. 同源

什么是同源?

如果两个页面的协议、域名端口都相同,那么这两个页面具有相同的源,也就是同源。

比如:

http://www.test.com/index 和 http://www.test.com/other.html 是同源,因为协议、端口和域名都相同。
http://www.test.com/index 和 https://www.test.com/other.html 不是同源,因为协议不同。

什么是同源策略?

官方定义:同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互,这是一个用于隔离潜在恶意文件的重要安全机制。

通俗理解:浏览器规定,A 网站的 JS,不允许和非同源网站 C 之间进行资源的交互。

比如:

无法读取非同源网页的 Cokkie、LocalStorage 和 IndexedDB。
无法接触非同源网页的 DOM。
无法向非同源地址发送 Ajax 请求。

2. 跨域

什么是跨域?

同源指的是两个 URL 的协议、域名、端口一致,反之就是跨域。出现跨域的根本原因是浏览器的同源策略不允许非同源的 URL 之间进行资源的交互。

网页: http://www.test.com/index.html 

接口: http://www.api.com/userlist

就是跨域。 

浏览器对跨域请求的拦截?

当 Ajax 向不同源的接口发起跨域请求时,请求可以正常发起,浏览器也能正常接收到跨域响应的数据。但是会被同源策略给拦截,从而无法被页面获取。

二、解决办法 

方法一:前端--使用代理

🔊:只适用于本地开发环境调试使用,上线了解决不了。上线时直接把dist放在后端服务器中,保证同源策略,避免出现跨域。

通过设置webpack proxy 或者 vite  proxy实现代理请求后,相当于浏览器与服务端中添加一个代理者

当本地发送请求的时候,代理服务器响应该请求,并将请求转发到目标服务器,目标服务器响应数据后再将数据返回给代理服务器,最终再由代理服务器将数据响应给本地

在代理服务器传递数据给本地浏览器的过程中,两者同源,并不存在跨域行为,这时候浏览器就能正常接收数据

⚠️ 注意:服务器与服务器之间请求数据并不会存在跨域行为,跨域行为是浏览器安全策略限制

我们这里以 Vite 的配置为例,来看一下如何给 API 请求设置代理。在 Vite 编写的项目里边,有一个 vite.config.js配置文件,里边是关于 Vite 的配置项,可以在里边配置代理。

假如我们前端项目路径为 http://localhost:3000,需要代理所有以 /api 开头的 API 请求,把它转发到 http://localhost:3001,并且后端的 API 路径中不带 /api前缀,需要自动去掉 /api前缀。

如下图所示:

那么可以使用下面这样的配置:

// vite.config.js
import { defineConfig } from "vite";
export default defineConfig({
  server: {
    proxy: {
      "/api": {
        target: "http://localhost:3001",
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api/, ""),
      },
    },
  },
});

在  vite 导出的配置里边:

  • 添加server 配置项。
  • 在 server配置项下边添加 proxy配置项,值为一个对象,属性名为要代理的 URL 路径段,值为相关的配置。
  • 这里属性名设置为 /api,来配置转发前端 http://localhost:3000/api 开头的所有请求路径。

在 proxy 配置对象中:

  • target,为实际的后端 URL,它会追加到属性名配置的 /api 这个片段的前面,例如访问 /api/some_end_point会转换为 http://localhost:3001/api/some_end_point
  • changeOrigin,是否改写 origin,设置为 true 之后,就会把请求 API header 中的 origin,改成跟 target 里边的域名一样了。
  • rewrite 可以把请求的 URL 进行重写,这里因为假设后端的 API 路径不带 /api 段,所以我们使用 rewrite去掉 /api。给 rewrite传递一个函数,函数的参数 path是前端请求的 API 路径,后面直接使用了 replace() 方法,在里面写一个正则表达式,把 /api开头的这一段替换为空。

这样 vite 的代理就配置好了。在实际前端请求的过程中,就可以直接使用 /api/some_endpoint这样的形式了:

fetch("/api/posts");

前面的 http 协议、域名和端口就都可以省略掉了,并且也没有了跨域的问题。

方法二:后端--设置 CORS

🔊:目前最主流、最简单的方案,直接让后端设置响应头,允许资源共享就ok了

如果你无法使用代理,也可以在接口的响应头中设置 CORS(跨域资源共享)。在后端代码中设置Access-Control-Allow-Origin 和其他相关的响应头,以允许跨域请求。

//调用方法创建一个服务器
  const app = express()
//解析json格式的请求体
  app.use(express.json())
//解析查询字符串格式的情趣 
  app.use(exoress.urlencoded({extended:true}))
//第一种: 使用中间件函数来设置cors允许资源共享
  app.use((req.res.next)=>{
    //设置响应头 告诉浏览器任何地址都可以访问这个接口
    res.setHeader('Access-Cosntrol-Allow-Origin','*')
    //告诉浏览器支持这些方式
    res.setHeader('Access-Cosntrol-Allow-Methods','GET,POST,DELETE,PUT')
    next()
  })
//第二种 推荐使用插件
const cors = require('cors')
app.use(cors())

posted on 2024-08-15 00:38  梁飞宇  阅读(65)  评论(0)    收藏  举报