'# ajax尚硅谷笔记——跨域请求、axios发送ajax请求、jquery发送ajax请求
一、背景与问题
在现代Web开发中,前后端分离架构成为主流。前端应用通常运行在https://frontend.com,后端API服务运行在https://api.example.com,这种跨域场景下会出现浏览器安全策略限制——同源策略(Same-Origin Policy)。
同源策略要求协议、域名、端口三者完全一致。当前端尝试访问https://api.example.com/data时,浏览器会阻止该请求,触发跨域错误(CORS错误)。这种限制的根本原因是浏览器为了防止恶意网站窃取用户数据。
典型场景:
- 前端使用Vue/React开发,后端使用Spring Boot/Node.js提供API
- 前端部署在CDN,后端API部署在独立服务器
- 前端使用第三方服务(如百度地图API)时
关键问题:
- 如何正确发送跨域请求
- 如何处理CORS预检请求(OPTIONS)
- 如何在实际项目中正确使用AJAX库
二、基本原理
1. 同源策略与CORS
同源策略是浏览器的强制安全措施,当请求的源(协议、域名、端口)与当前页面不同,浏览器会阻止请求。CORS(跨域资源共享)是W3C标准,通过在响应头中添加Access-Control-Allow-Origin字段来允许跨域请求。
Access-Control-Allow-Origin: https://frontend.com2. JSONP与CORS
JSONP是一种古老的跨域方案,通过动态创建<script>标签实现。但存在严重安全缺陷(无法处理复杂数据类型),已被CORS方案取代。
3. 预检请求(Preflight)
对于非简单请求(如携带Content-Type: application/json的POST请求),浏览器会先发送OPTIONS请求,检查服务器是否允许跨域。服务器需返回:
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST
Access-Control-Allow-Headers: Content-Type三、环境准备
1. 开发环境搭建
# 创建项目目录
mkdir cors-demo && cd cors-demo
# 初始化Node.js项目
npm init -y
# 安装Express和cors中间件
npm install express cors2. 后端服务器配置
// server.js
const express = require('express');
const cors = require('cors');
const app = express();
// 允许所有来源的跨域请求
app.use(cors());
// 模拟数据接口
app.get('/data', (req, res) => {
res.json({
status: 'success',
data: [1, 2, 3]
});
});
// 启动服务
app.listen(3000, () => {
console.log('Server running at http://localhost:3000');
});四、核心实现
1. 使用Axios发送跨域请求(推荐方案)
// index.html
<!DOCTYPE html>
<html>
<head>
<title>Axios跨域示例</title>
</head>
<body>
<div id="result"></div>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
axios.get('http://localhost:3000/data')
.then(response => {
document.getElementById('result').innerText = JSON.stringify(response.data);
})
.catch(error => {
console.error('请求失败:', error);
});
</script>
</body>
</html>关键代码解释:
axios.get()自动处理CORS预检请求- 使用
try-catch捕获异常 - 响应数据通过
response.data访问
2. 使用jQuery发送跨域请求
// index.html
<!DOCTYPE html>
<html>
<head>
<title>jQuery跨域示例</title>
</head>
<body>
<div id="result"></div>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script>
$.ajax({
url: 'http://localhost:3000/data',
type: 'GET',
success: function(data) {
$('#result').text(JSON.stringify(data));
},
error: function(xhr, status, error) {
console.error('请求失败:', status, error);
}
});
</script>
</body>
</html>关键代码解释:
$.ajax()配置对象包含请求参数success回调处理成功响应error回调处理错误(包括CORS错误)
3. 使用JSONP(不推荐)
<script src="http://localhost:3000/data?callback=handleData"></script>
<script>
function handleData(data) {
console.log('JSONP响应:', data);
}
</script>注意:JSONP需要服务器显式支持回调函数,且存在安全风险。
五、完整案例
1. 实现一个完整的跨域请求案例
项目结构:
cors-demo/
├── server.js
├── index.html
└── package.json前端页面(index.html):
<!DOCTYPE html>
<html>
<head>
<title>完整跨域案例</title>
</head>
<body>
<h2>跨域请求示例</h2>
<div id="result"></div>
<button onclick="sendRequest()">发送请求</button>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
function sendRequest() {
axios.get('http://localhost:3000/data')
.then(response => {
const result = document.getElementById('result');
result.innerHTML = `
<pre>状态码: ${response.status}<br>
响应数据: ${JSON.stringify(response.data)}</pre>
`;
})
.catch(error => {
console.error('请求失败:', error);
alert('请求失败,请检查控制台');
});
}
</script>
</body>
</html>后端配置(server.js):
const express = require('express');
const cors = require('cors');
const app = express();
// 启用CORS中间件
app.use(cors({
origin: 'http://localhost:3000', // 允许的前端源
methods: ['GET', 'POST'],
allowedHeaders: ['Content-Type']
}));
// 模拟数据接口
app.get('/data', (req, res) => {
res.json({
status: 'success',
data: [1, 2, 3]
});
});
// 启动服务
app.listen(3000, () => {
console.log('Server running at http://localhost:3000');
});运行步骤:
- 启动后端服务:
node server.js - 在浏览器中打开
index.html - 点击"发送请求"按钮
- 查看控制台输出和页面结果
六、源码解析
1. Axios源码核心机制
Axios通过Axios类封装请求逻辑,关键代码如下:
// axios.js
class Axios {
constructor(instanceConfig) {
this.defaults = new Axios.defaults(instanceConfig);
this.interceptors = {
request: {
handlers: [],
queue: []
},
response: {
handlers: [],
queue: []
}
};
}
request(config) {
// 处理请求拦截器
this.interceptors.request.handlers.forEach(handler => {
config = handler(config);
});
// 发送请求
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open(config.method, config.url, true);
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
const response = {
data: xhr.responseText,
status: xhr.status,
statusText: xhr.statusText
};
resolve(response);
}
};
xhr.send();
});
}
}关键点:
- 使用
XMLHttpRequest封装请求 - 支持拦截器机制(请求前/响应后处理)
- 自动处理CORS预检请求
2. jQuery AJAX源码核心
jQuery的$.ajax()通过$.ajaxTransport()处理跨域请求:
// jquery-ajax.js
$.ajaxTransport(function( type ) {
if ( type === "GET" ) {
return {
send: function( headers, callback ) {
var url = (location.protocol + "//" + location.host + "/" + $.ajaxSettings.url)
.replace( /^.*?([/?#].*)$/, "$1" );
var xhr = new XMLHttpRequest();
xhr.open( "GET", url, true );
xhr.onreadystatechange = function() {
if ( xhr.readyState === 4 ) {
callback( xhr.status, xhr.statusText, xhr.responseText );
}
};
xhr.send();
},
headers: {}
};
}
});关键点:
- 使用
XMLHttpRequest对象 - 通过
$.ajaxSettings配置全局参数 - 支持各种HTTP方法和请求头
七、进阶使用
1. 复杂请求处理
// 发送带token的POST请求
axios.post('http://localhost:3000/api', {
data: 'test'
}, {
headers: {
'Authorization': 'Bearer your_token_here'
}
})
.then(response => {
console.log('响应数据:', response.data);
})
.catch(error => {
console.error('错误:', error.response ? error.response.data : error);
});2. 文件上传
// 上传文件
const formData = new FormData();
formData.append('file', fileInput.files[0]);
axios.post('http://localhost:3000/upload', formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
})
.then(response => {
console.log('上传结果:', response.data);
});3. 跨域认证
// 设置Cookie
axios.get('http://localhost:3000/data', {
withCredentials: true
})
.then(response => {
console.log('带Cookie的响应:', response.data);
});八、性能与工程实践
1. 性能优化
- 减少跨域请求次数:合并多个API请求
- 使用缓存:通过
Cache-Control头控制缓存策略 - 压缩数据:使用Gzip或Brotli压缩响应体
- 减少传输体积:使用JSON格式,避免XML
2. 异常处理
axios.get('http://localhost:3000/data')
.catch(error => {
// 处理网络错误
if (error.response) {
// 响应成功但状态码 >= 400
console.error('服务器响应错误:', error.response.status);
} else if (error.request) {
// 请求未收到响应
console.error('请求未收到响应:', error.request);
} else {
// 请求配置错误
console.error('请求配置错误:', error.message);
}
});3. 安全实践
严格限制CORS来源:
app.use(cors({ origin: 'https://frontend.com' }));- 防止CSRF攻击:使用
withCredentials: false和SameSite属性 - 避免暴露敏感信息:不要在响应头中泄露服务器信息
九、常见问题与踩坑
1. 预检请求失败
错误示例:
// 未处理OPTIONS请求
app.get('/data', (req, res) => {
res.json({ status: 'success' });
});解决方案:
// 处理OPTIONS请求
app.options('/data', (req, res) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET, POST');
res.header('Access-Control-Allow-Headers', 'Content-Type');
res.status(200).send();
});2. 跨域携带Cookie失败
错误场景:未设置withCredentials: true或未配置Access-Control-Allow-Credentials
解决方案:
axios.get('http://localhost:3000/data', {
withCredentials: true
})3. JSONP回调函数名错误
错误示例:
<script src="http://localhost:3000/data?callback=myCallback"></script>
<script>
function myCallback(data) { ... }
</script>解决方案:确保回调函数名与URL参数一致
十、最佳实践
1. 推荐方案
- 优先使用Axios:现代项目首选,支持Promise、拦截器、自动CORS处理
- jQuery作为备用方案:适用于需要兼容旧浏览器的项目
- 避免JSONP:安全性和功能限制较大
2. 使用建议
- 在需要现代API时:使用Axios的
async/await语法 - 在需要兼容性时:使用jQuery的回调函数机制
- 在需要安全控制时:严格配置CORS策略
3. 避免使用场景
- 不要在单页应用中频繁发送跨域请求:考虑前端缓存策略
- 不要在服务器端暴露CORS头:防止被恶意网站利用
- 不要在公共接口中使用
withCredentials: true:可能导致CSRF风险
十一、总结
跨域请求是现代Web开发中不可避免的挑战,理解其原理(同源策略、CORS机制)是解决问题的关键。Axios和jQuery提供了不同的实现方式:Axios更适合现代项目,支持Promise和拦截器;jQuery更适合需要兼容性支持的场景。
实际开发中需要根据项目需求选择合适的方案,同时注意安全配置(如限制CORS来源、防止CSRF)。对于性能优化,可以采用缓存、压缩等手段,而对于复杂场景(如文件上传、认证),需要合理使用请求头和拦截器。
通过本文的深入分析和完整案例,开发者可以更好地理解跨域请求的实现原理,避免常见错误,并在实际项目中做出更合理的技术选型。