Vue学习记录之二十六 Vue3中跨域

跨域(Cross-Origin)指的是浏览器的同源策略(Same-Origin Policy)限制了一个源(域、协议和端口)下的 JavaScript 脚本访问另一个源的资源。为了保护用户数据的安全,浏览器默认禁止网页向其他域发送请求或访问资源,这种限制称为跨域限制。

1. 同源策略

同源策略要求以下三者相同才算同源:

  • 协议:如 httphttps
  • 域名:如 example.com
  • 端口:如 :80:443

例如:

  • http://example.comhttps://example.com 是跨域的(协议不同)。
  • http://example.comhttp://sub.example.com 是跨域的(域名不同)。
  • http://example.com:80http://example.com:8080 是跨域的(端口不同)。

2. 常见的跨域场景

  • API 请求:前端应用需要向不同的 API 域名请求数据,例如从 http://localhost:3000 请求 http://api.example.com
  • CDN 资源加载:网站从其他域名的 CDN 加载静态资源。
  • 嵌套页面:通过 <iframe> 加载不同源的网页内容。

3. 解决跨域问题的方法

(1)CORS(跨域资源共享)

W3C标准,服务器可以通过设置 Access-Control-Allow-Origin 头部来允许跨域请求。CORS 是目前最主流的跨域解决方案,允许服务器设置哪些域可以访问其资源。IE不能低于IE10。主要用于服务端的配置。需要浏览器和服务器端同时支持。
可以使用中间件:cors

示例:

Access-Control-Allow-Origin: http://example.com
//或者
"Access-Control-Allow-Origin": "*"   //使用通配符,任何地址都可以访问,但安全性不高。

实例:
建立一个新的文件夹,使用 npm init 生成 package.json, 安装依赖

pnpm install koa -D   #koa模块
pnpm install koa-router -D # 路由模块
pnpm install koa2-cors -D  # 中间件模块
npm install -g nodemon #是一个实用程序,它监视 Node.js 应用程序中的文件变化,并在检测到变化时自动重新启动应用程序。它非常适合开发环境,因为它节省了手动重启服务器的时间和精力。 热启动

app.js

/*
1、http: Node.js 的核心模块,提供基本的 HTTP 功能,如创建服务器、处理请求和响应。它较为底层,使用时需要手动处理很多细节。
2、Express: 基于 http 的框架,简化了 HTTP 服务器的构建。它提供了更高层的 API,使路由、请求处理和中间件的使用更加便捷。适合快速开发 RESTful API 和 web 应用。
3、Koa: 由 Express 的创建者开发,是一个更轻量级且现代化的框架。Koa 使用 async/await 语法,允许更优雅的错误处理和中间件链管理。它的设计目标是更小、更强大、可扩展性更高。
*/
const Koa = require('koa')
const cors = require('koa2-cors')  //中间件
const app = new Koa()

const index = require('./router/index')
//实际开发中会配置域名白名单,只允许这些域名发起请求。
app.use(cors({
    
    
    origin: '*', // 相当于Access-Control-Allow-Origin:允许所有源,或者你可以指定特定的源如 'http://example.com'
    allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'],
    allowHeaders: ['Content-Type', 'Authorization', 'Accept'],
}))
//将路由注册到应用。
app.use(index.routes(), index.allowedMethods())
//启动监听
app.listen(3001,()=>{
    
    
    console.log('http://localhost:3001')
})

在router目录下index.js

const Router = require('koa-router')
const router = new Router()

router.prefix('/api')
router.get('/index',ctx=>{
    
    
    return (ctx.body={
    
    
        code: 200,
        message: 'ok'
    })
})
//http://localhost:3001/api/index
/*
router.get('/', async (ctx) => {
  ctx.body = 'Welcome to Koa!';
});
*/
module.exports = router

启动:

(2)JSONP(JSON with Padding)

JSONP 是一种较旧的跨域方式,适用于 GET 请求。它通过 <script> 标签加载数据,将响应包装为 JavaScript 函数调用。他是基于src 不受同源策略限制。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
<div id="result"></div>
<div>ddfdsf</div>
</body>
<script>
window.onload = function(){
      
      
	let obj,s
	//obj = {'table':'products', 'limit':10} //添加参数
	s = document.createElement('script') //动态创建script
	//指定请求的 URL,并在 URL 中添加 callback 参数
	//相当于callbackFunctions({'table':'products', 'limit':10})
	//s.src = 'https://www.runoob.com/try/ajax/jsonp.php?jsoncallback=callbackFunctions' + JSON.stringify(obj);
	s.src = 'https://www.runoob.com/try/ajax/jsonp.php?jsoncallback=callbackFunctions'
	document.body.appendChild(s)
}

function callbackFunctions(data){
      
      
    console.log('ok')
    console.log(data)
    document.getElementById('result').innerHTML = JSON.stringify(data)
}
</script>
</html>

使用Vite proxy 或者 node代理 或者 webpack proxy 他们三种方式都是代理

(3)代理服务器

通过设置代理服务器,浏览器请求首先发送到同源的代理服务器,再由代理服务器请求目标域,从而实现跨域。

某些服务器可能在配置上允许任何来源访问资源,即在响应头中设置 Access-Control-Allow-Origin: *。这种配置允许来自任何来源的跨域请求,无需浏览器进行额外的权限校验。不过,这通常限于不包含敏感信息的资源,以防止安全隐患。不需要设置跨域,也能访问。

server: {
    
    
    proxy: {
    
    
      // 字符串简写写法
      '/foo': 'http://localhost:4567',
      // 选项写法
      '/api': {
    
    
        target: 'http://jsonplaceholder.typicode.com',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api/, '')
      },
      // 正则表达式写法
      '^/fallback/.*': {
    
    
        target: 'http://jsonplaceholder.typicode.com',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/fallback/, '')
      },
      // 使用 proxy 实例
      '/api': {
    
    
        target: 'http://jsonplaceholder.typicode.com',
        changeOrigin: true,
        configure: (proxy, options) => {
    
    
          // proxy 是 'http-proxy' 的实例
        }
      }
    }
  }
// vite.config.js
import {
    
     defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';

export default defineConfig({
    
    
  plugins: [vue()],
  server: {
    
    
    proxy: {
    
    
      // 当请求以 /api 开头时,代理到 https://api.example.com
      '/api': {
    
    
        target: 'https://api.example.com',
        changeOrigin: true, // 允许跨域
        //用于重写路径。例如,将/api前缀去除,
        //使得请求发送到https://api.example.com/, 而不是https://api.example.com/api。
        rewrite: (path) => path.replace(/^\/api/, ''), // 将 /api 去掉
      },
    },
  },
});

使用:

mport axios from 'axios';

export function fetchData() {
    
    
  // 在代码中调用API时,只需使用配置的代理路径即可,不需要指定完整的后端地址
  return axios.get('/api/data'); // 只需要使用 /api,Vite 会自动代理
}
  server:{
    
    
    proxy: {
    
    
      '/API/zs_zdbs.php':{
    
    
        target:'https://xiaoapi.cn',    //https://xiaoapi.cn/API/zs_zdbs.php
        changeOrigin: true,
      }
    }
  },

使用

axios.get('/API/zs_zdbs.php?h=24')
.then(res=>{
    
    
  console.log(res.data)
})
(4)后端设置

可以在服务端设置 Nginx 或其他代理服务器,通过将跨域请求代理到目标服务器,避免浏览器的跨域限制。
Apache 配置(在虚拟主机配置文件中添加):

<VirtualHost *:80>
    ServerName yourdomain.com

    ProxyPass /api/ http://api.example.com/
    ProxyPassReverse /api/ http://api.example.com/

    Header set Access-Control-Allow-Origin "*"
    Header set Access-Control-Allow-Methods "GET, POST, OPTIONS"
    Header set Access-Control-Allow-Headers "Origin, Content-Type, Accept, Authorization"

    <Location "/api/">
        SetEnvIf Request_Method OPTIONS OPTIONS_REQUEST
        Header set Access-Control-Allow-Origin "*"
        Header set Access-Control-Allow-Methods "GET, POST, OPTIONS"
        Header set Access-Control-Allow-Headers "Origin, Content-Type, Accept, Authorization"
        Header always set Access-Control-Max-Age "1000"
        Header always set Content-Length "0"
        Header always set Content-Type "text/plain charset=UTF-8"
        <IfModule mod_rewrite.c>
            RewriteEngine On
            RewriteCond %{
    
    REQUEST_METHOD} OPTIONS
            RewriteRule ^(.*)$ $1 [R=200,L]
        </IfModule>
    </Location>
</VirtualHost>


(5)WebSocket

WebSocket 不受同源策略限制,可以实现跨域通信,但需要服务器和客户端的支持。

4. 跨域的常见错误和影响

  • No ‘Access-Control-Allow-Origin’ header:当服务器未设置允许的源时,浏览器会阻止请求。
  • 预检请求(Preflight Request)失败:对于复杂请求(如 PUTDELETE 等),浏览器会首先发送预检请求,验证服务器是否允许该请求。

5. 总结

跨域是浏览器出于安全考虑限制不同源之间资源请求的机制。通过 CORS、JSONP、代理等方式可以实现跨域通信。

猜你喜欢

转载自blog.csdn.net/LvManBa/article/details/143278570