大白话跨域问题怎么破,解决方法有啥?
啥是跨域问题
咱先说说啥是跨域。你可以把每个网站想象成一个独立的小房子,每个房子都有自己的地址(也就是域名)。正常情况下,一个房子里的东西只能在这个房子里用,不能随便跑到别的房子里去。在网页开发里,浏览器有个“同源策略”,就像规定了房子和房子之间不能随便串门。如果一个网页要从它所在的域名去访问另一个域名下的资源,这就相当于要从一个房子跑到另一个房子去拿东西,浏览器就会阻止这种行为,这就是跨域问题。比如说,你在 http://www.example1.com
这个网站的页面里,想访问 http://www.example2.com
网站的接口数据,就会遇到跨域问题。
解决方法
1. JSONP(JSON with Padding)
- 原理:JSONP 利用了
<script>
标签的 src 属性不受同源策略限制的特点。就好比<script>
标签有个特殊通行证,可以去别的房子拿东西。服务器返回的数据会被包裹在一个回调函数里,网页通过<script>
标签请求这个带有回调函数的脚本,拿到数据后就可以在回调函数里处理。 - 代码示例
- 服务器端(Node.js + Express)
const express = require('express');
const app = express();app.get('/data', (req, res) => {const callback = req.query.callback;const data = { message: '这是从服务器返回的数据' };const jsonp = `${callback}(${JSON.stringify(data)})`;res.send(jsonp);
});const port = 3000;
app.listen(port, () => {console.log(`服务器运行在端口 ${port}`);
});
- **客户端(HTML + JavaScript)**
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF - 8">
</head><body><script>function handleData(data) {console.log(data.message);}const script = document.createElement('script');script.src = 'http://localhost:3000/data?callback=handleData';document.body.appendChild(script);</script>
</body></html>
- 优缺点
- 优点:兼容性好,几乎所有浏览器都支持。
- 缺点:只支持 GET 请求,安全性较低,容易受到 XSS 攻击。
2. CORS(Cross - Origin Resource Sharing,跨域资源共享)
- 原理:CORS 是一种现代的跨域解决方案,它是服务器端的一种机制。服务器通过设置响应头,告诉浏览器哪些域名可以访问它的资源,浏览器看到这些响应头后,就会允许跨域请求。就好比房子的主人给某些房子发了邀请函,拿到邀请函的房子里的人就可以来串门了。
- 代码示例
- 服务器端(Node.js + Express)
const express = require('express');
const app = express();// 设置 CORS 响应头
app.use((req, res, next) => {res.setHeader('Access - Control - Allow - Origin', '*'); // 允许所有域名访问res.setHeader('Access - Control - Allow - Methods', 'GET, POST, PUT, DELETE');res.setHeader('Access - Control - Allow - Headers', 'Content - Type');next();
});app.get('/data', (req, res) => {const data = { message: '这是从服务器返回的数据' };res.json(data);
});const port = 3000;
app.listen(port, () => {console.log(`服务器运行在端口 ${port}`);
});
客户端(HTML + JavaScript)
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF - 8">
</head><body><script>fetch('http://localhost:3000/data').then(response => response.json()).then(data => console.log(data.message));</script>
</body></html>
- 优缺点
- 优点:支持各种 HTTP 请求方法(GET、POST 等),安全性高。
- 缺点:需要服务器端进行配置,对于一些老旧服务器可能不支持。
3. 代理服务器
- 原理:代理服务器就像一个中间人。客户端把请求发给代理服务器,代理服务器再把请求转发给目标服务器,拿到目标服务器的响应后,再把响应返回给客户端。因为代理服务器和客户端在同一个域名下,所以不存在跨域问题。就好比你想从另一个房子拿东西,你把请求告诉一个住在你家附近的朋友,这个朋友去帮你从那个房子里把东西拿回来给你。
- 代码示例(开发环境下使用 Webpack 代理)
- Webpack 配置文件
const path = require('path');
const webpack = require('webpack');
const { WebpackDevServer } = require('webpack - dev - server');const config = {// 其他配置...devServer: {proxy: {'/api': {target: 'http://localhost:3000', // 目标服务器地址changeOrigin: true,pathRewrite: { '^/api': '' }}}}
};const compiler = webpack(config);
const server = new WebpackDevServer(compiler, config.devServer);
server.listen(8080, 'localhost', () => {console.log('开发服务器运行在端口 8080');
});
- **客户端(HTML + JavaScript)**
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF - 8">
</head><body><script>fetch('/api/data').then(response => response.json()).then(data => console.log(data.message));</script>
</body></html>
- 优缺点
- 优点:不需要服务器端进行额外配置,适合开发环境。
- 缺点:需要搭建代理服务器,增加了系统复杂度。
啥是跨域问题
咱先把跨域问题说明白。你可以把每个网站想象成不同的小区,每个小区都有自己的门禁系统(也就是浏览器的同源策略)。同源策略规定,只有同一个小区(也就是域名、端口、协议都相同)里的住户(页面资源)才能自由交流。要是一个小区的住户想和另一个小区的住户通信,就会被门禁拦住,这就是跨域问题。在前端开发里,当你用 React 或者 Vue 3 写的页面想去请求另一个域名下的接口数据时,就会遇到这种情况。
React 框架跨域问题及解决办法
开发环境下用代理服务器解决
- 原理:在开发的时候,就好比你请了一个跑腿小哥。你把请求交给这个小哥,小哥拿着你的请求去另一个小区(目标服务器)帮你办事,然后把结果带回来给你。因为小哥是你们小区(本地开发服务器)的人,所以能顺利进出,这样就绕过了门禁(同源策略)。
- 操作步骤
- 如果你用
create - react - app
创建的项目,在package.json
文件里加一行配置。比如目标服务器地址是http://api.example.com
,就在package.json
里加上"proxy": "http://api.example.com"
。这就相当于告诉跑腿小哥他要去的地方。 - 在 React 代码里发请求。比如你要请求
http://api.example.com/api/data
这个接口,代码里就写fetch('/api/data')
。因为有了前面的配置,开发服务器会自动把这个请求转发到目标服务器。
- 如果你用
import React, { useEffect } from'react';function App() {useEffect(() => {async function getData() {try {const response = await fetch('/api/data');const data = await response.json();console.log(data);} catch (error) {console.error('请求出错啦:', error);}}getData();}, []);return (<div><h1>React 跨域请求示例</h1></div>);
}export default App;
生产环境用 CORS 解决
- 原理:到了正式上线的生产环境,就不能用跑腿小哥了。这时候得让另一个小区(目标服务器)的门卫(服务器)给你发个通行证。服务器通过设置一些特殊的响应头,告诉浏览器你的小区(域名)可以访问它的资源。
- 操作步骤
- 服务器端设置。假设目标服务器用 Node.js 和 Express 搭建,在代码里加上下面这些设置:
const express = require('express');
const app = express();// 设置允许访问的域名
app.use((req, res, next) => {res.setHeader('Access - Control - Allow - Origin', 'http://your - react - app.com'); res.setHeader('Access - Control - Allow - Methods', 'GET, POST, PUT, DELETE');res.setHeader('Access - Control - Allow - Headers', 'Content - Type');next();
});app.get('/api/data', (req, res) => {const data = { message: '这是服务器返回的数据' };res.json(data);
});const port = 3000;
app.listen(port, () => {console.log('服务器在端口 3000 运行');
});
- 在 React 代码里正常发请求就行。
import React, { useEffect } from'react';function App() {useEffect(() => {async function getData() {try {const response = await fetch('http://api.example.com/api/data');const data = await response.json();console.log(data);} catch (error) {console.error('请求出错啦:', error);}}getData();}, []);return (<div><h1>React 跨域请求示例</h1></div>);
}export default App;
Vue 3 框架跨域问题及解决办法
开发环境用代理服务器解决
- 原理:和 React 开发环境一样,也是请个跑腿小哥。Vue 3 一般用 Vue CLI 来开发,Vue CLI 的开发服务器能充当这个跑腿小哥。
- 操作步骤
- 在
vue.config.js
文件里配置代理。比如目标服务器是http://api.example.com
,文件内容可以这样写:
- 在
module.exports = {devServer: {proxy: {'/api': {target: 'http://api.example.com',changeOrigin: true,pathRewrite: { '^/api': '' }}}}
};
这里的 `/api` 是你本地请求的前缀,`target` 是目标服务器地址,`changeOrigin` 表示是否改变请求的源,`pathRewrite` 是对请求路径进行重写。
- 在 Vue 3 组件里发请求。
<template><div><h1>Vue 3 跨域请求示例</h1></div>
</template><script setup>
import { onMounted } from 'vue';onMounted(async () => {try {const response = await fetch('/api/data');const data = await response.json();console.log(data);} catch (error) {console.error('请求出错啦:', error);}
});
</script>
生产环境用 CORS 解决
- 原理:同样是让目标服务器的门卫发通行证。
- 操作步骤
- 服务器端设置和前面 React 生产环境的服务器设置一样。
- 在 Vue 3 组件里正常发请求。
<template><div><h1>Vue 3 跨域请求示例</h1></div>
</template><script setup>
import { onMounted } from 'vue';onMounted(async () => {try {const response = await fetch('http://api.example.com/api/data');const data = await response.json();console.log(data);} catch (error) {console.error('请求出错啦:', error);}
});
</script>