一、基础篇
跨域问题产生
跨域(Cross-Origin)是指在浏览器的同源策略(Same-Origin Policy)下,当一个网页尝试加载来自不同域名(协议、域名、端口有一个不同)的资源时,会出现跨域问题。同源策略是浏览器的一项安全策略,用于防止恶意网站从其他站点获取敏感数据。跨域问题的产生主要有以下原因:
- 安全性: 同源策略是为了保护用户隐私和数据安全而制定的。如果没有同源策略,恶意网站可能会轻松获取到其他网站的用户数据。
- 隔离数据: 同源策略有助于隔离不同网站的数据,防止不同网站之间的数据混合在一起,导致数据污染和安全问题。
- 跨域请求风险: 如果浏览器允许跨域请求,那么网站可能会被攻击者滥用,发起恶意请求,例如 CSRF(跨站请求伪造)攻击。
下面是一些常见产生跨域问题的情况:
- 协议不同: 如果网页使用 HTTP 协议加载资源,但资源使用 HTTPS 协议,就会产生跨域问题。
- 域名不同: 如果网页在一个域名上加载资源,但资源在另一个域名上,就会产生跨域问题。
- 端口不同: 如果网页使用不同的端口加载资源,也会产生跨域问题。
- 子域名不同: 同源策略也将子域名视为不同的域,例如,
example.com和sub.example.com被视为不同的域。 - JavaScript 的限制: 使用 XMLHttpRequest 或 Fetch API 发起跨域请求时,浏览器会检查请求的域是否符合同源策略。
解决跨域问题办法
1. JSONP(仅限GET请求):
<script>
function handleResponse(data) {
console.log('Response:', data);
}
</script>
<script src="http://example.com/api/data?callback=handleResponse"></script>
在这个示例中,我们定义了一个名为 handleResponse 的JavaScript函数,然后通过<script>标签请求目标服务器的数据,该数据以回调函数的形式返回。请确保在目标服务器上支持JSONP请求。
vue项目里使用:
// 使用Vue Resource库
import Vue from 'vue';
import VueResource from 'vue-resource';
Vue.use(VueResource);
Vue.http.jsonp('http://example.com/api/data').then(response => {
// 处理JSONP响应数据
});
2. CORS(跨源资源共享):
前端无需额外的代码来处理CORS,因为CORS配置是在服务器端完成的。确保目标服务器正确配置CORS标头以允许你的前端域名进行跨域请求。以下是一个示例CORS配置:
// Express.js服务器端示例
const express = require('express');
const cors = require('cors');
const app = express();
// 允许特定源的请求
app.use(cors({
origin: 'http://your-frontend-app.com',
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
credentials: true, // 允许跨域请求携带凭证(例如,使用Cookie)
}));
// 处理跨域请求
app.get('/api/data', (req, res) => {
res.json({ message: 'Hello from the server!' });
});
const port = 3000;
app.listen(port, () => {
console.log(`Server is running on port ${port}`);
});
前端无需额外代码,只需在前端应用中发送请求到服务器。
3. WebSocket连接:
WebSocket示例需要使用WebSocket客户端库,例如socket.io。以下是一个简化的WebSocket示例:
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.js"></script>
<script>
const socket = io('http://example.com'); // 连接到WebSocket服务器
socket.on('connect', () => {
console.log('Connected to WebSocket');
});
socket.on('message', (data) => {
console.log('Received message:', data);
});
// 发送消息
socket.emit('message', 'Hello, server!');
</script>
在这个示例中,我们使用了socket.io库来建立WebSocket连接,并通过WebSocket发送和接收消息。
4. 跨文档消息传递(PostMessage):
window.postMessage()方法允许你在不同窗口或iframe之间安全地传递消息。以下是一个简化的示例:
<!-- 在iframe的父窗口中 -->
<iframe src="http://example.com/iframe"></iframe>
<script>
const iframe = document.querySelector('iframe');
// 向iframe发送消息
iframe.contentWindow.postMessage('Hello from parent!', 'http://example.com');
</script>
<!-- 在iframe中 -->
<script>
window.addEventListener('message', (event) => {
if (event.origin === 'http://example.com') {
console.log('Received message from parent:', event.data);
}
});
</script>
在这个示例中,父窗口通过postMessage()向iframe发送消息,iframe监听message事件来接收消息。
请根据你的具体需求选择适当的方法,并确保在服务器端进行适当的配置(例如CORS配置)以支持跨域请求。前端示例只是演示如何处理跨域的基本方法。
二、在vue项目里处理跨域(反向代理)
- 在Vue项目的根目录下创建一个
vue.config.js文件(如果已经存在,请忽略此步骤)。 - 在
vue.config.js文件中添加以下内容:
module.exports = {
devServer: {
proxy: {
// 代理配置
'/api': {
target: process.env.VUE_APP_API_BASE_URL, // 使用环境变量作为目标服务器URL
changeOrigin: true,
pathRewrite: {
'^/api': '',
},
},
},
},
};
在上面的示例中,我们使用了process.env.VUE_APP_API_BASE_URL作为目标服务器的URL,这个环境变量是从Vue项目的.env文件中读取的。
3.在Vue项目的根目录下创建一个.env文件,以定义环境变量:
VUE_APP_API_BASE_URL=http://example.com/api
在这个示例中,我们将VUE_APP_API_BASE_URL设置为目标服务器的URL。
4.axios二次封装 当封装Axios时,你可以添加请求拦截器和响应拦截器来全局处理请求和响应。这使你能够在每个请求之前和每个响应之后执行一些操作,例如设置请求头、处理错误等。以下是如何在封装Axios时添加请求拦截和响应拦截的示例:
// api.js
import axios from 'axios';
const instance = axios.create({
baseURL: process.env.VUE_APP_API_BASE_URL,
timeout: 10000,
headers: {
'Content-Type': 'application/json',
},
});
// 请求拦截器
instance.interceptors.request.use(
config => {
// 在请求发送之前做一些操作,例如添加请求头
config.headers.Authorization = 'Bearer ' + getToken(); // 示例:添加身份验证令牌
return config;
},
error => {
// 处理请求错误
return Promise.reject(error);
}
);
// 响应拦截器
instance.interceptors.response.use(
response => {
// 在响应数据之前做一些操作
return response;
},
error => {
// 处理响应错误
if (error.response) {
// 如果服务器返回错误状态码,可以在这里处理
console.error('HTTP Error:', error.response.status);
} else if (error.request) {
// 请求发出但没有收到响应
console.error('Request Error:', error.request);
} else {
// 其他错误
console.error('Error:', error.message);
}
return Promise.reject(error);
}
);
export default instance;
在上面的示例中,我们通过interceptors属性添加了请求拦截器和响应拦截器。
- 请求拦截器(
interceptors.request)用于在每个请求发送之前执行操作。这里我们示例性地添加了身份验证令牌到请求头中。 - 响应拦截器(
interceptors.response)用于在每个响应到达之后执行操作。在这里,你可以处理响应数据或错误。
在Vue项目中,你只需导入这个封装好的Axios实例(例如,在userService.js中导入),然后使用它来发送请求,拦截器会自动应用到每个请求和响应中。
// userService.js
import axios from './api';
export default {
getUserById(id) {
return axios.get(`/users/${id}`);
},
updateUser(id, data) {
return axios.put(`/users/${id}`, data);
},
// 可以添加其他API请求方法
};