刚入行写前端的时候,我也被这个404错误虐过无数遍。那时候看着控制台里红色的“404 Not Found”,心里那个慌啊,明明路径是对的,参数也传了,为什么就是找不到页面?后来踩了无数的坑,才慢慢摸清了jQuery ajax的门道。今天就把我总结的经验毫无保留地分享给你,保证你看完后能彻底解决这个烦恼。
为什么你的ajax请求会报404?
先别急着改代码,咱们得先搞清楚问题出在哪。404错误本质上就是服务器找不到你请求的资源。在ajax请求里,这通常有以下几个原因:
最常见的原因:URL路径写错了
// 错误写法:相对路径处理不当
$.ajax({
url: 'api/user/list', // 如果当前页面是 http://example.com/admin/index.html
// 实际请求会变成 http://example.com/admin/api/user/list,而不是你期望的 http://example.com/api/user/list
type: 'GET',
success: function(data) {
console.log(data);
}
});
// 正确写法:使用绝对路径或正确的相对路径
$.ajax({
url: '/api/user/list', // 根路径下的API
type: 'GET',
success: function(data) {
console.log(data);
}
});
第二个坑:请求方法不匹配
很多时候后端接口规定只能用POST,你却用了GET,或者反过来。有些服务器配置对请求方法敏感,方法不对就会返回404(而不是常见的405 Method Not Allowed)。
// 后端接口要求POST,你用了GET,就可能404
$.ajax({
url: '/api/user/create',
type: 'GET', // 错误!应该是POST
data: { name: '张三', age: 25 },
success: function(data) {
console.log(data);
}
});
// 正确写法
$.ajax({
url: '/api/user/create',
type: 'POST', // 正确!
data: { name: '张三', age: 25 },
success: function(data) {
console.log(data);
}
});
第三个原因:静态资源路径问题
如果你请求的是图片、CSS、JS文件,而不是API接口,404往往是因为文件路径不对。
// 错误:路径层次关系搞错了
$.ajax({
url: '../api/config.json', // 假设当前页面在 /pages/user/profile.html
// 实际解析为 /pages/api/config.json,但文件可能在 /api/config.json
type: 'GET',
success: function(config) {
console.log(config);
}
});
// 正确:使用绝对路径或正确的相对路径
$.ajax({
url: '/api/config.json', // 从根目录开始
type: 'GET',
success: function(config) {
console.log(config);
}
});
jQuery ajax完整参数详解
搞清楚了404的原因,咱们来系统学习一下jQuery ajax的各种参数。别被这么多参数吓到,我一个个给你讲明白。
基础参数配置
$.ajax({
// 1. 请求URL(必填)
url: '/api/user/list',
// 2. 请求类型(可选,默认GET)
type: 'GET', // 也可以是 'POST', 'PUT', 'DELETE', 'PATCH'
// 3. 发送的数据
data: {
page: 1,
pageSize: 10,
keyword: 'jQuery'
},
// 4. 期望服务器返回的数据类型
dataType: 'json', // 'xml', 'html', 'text', 'json', 'jsonp', 'script'
// 5. 是否异步(可选,默认true)
async: true,
// 6. 超时时间(毫秒,可选)
timeout: 5000,
// 7. 请求头设置
headers: {
'Authorization': 'Bearer your_token_here',
'Content-Type': 'application/json'
},
// 8. 成功回调
success: function(response, textStatus, jqXHR) {
console.log('请求成功!', response);
},
// 9. 错误回调
error: function(jqXHR, textStatus, errorThrown) {
console.error('请求失败:', textStatus, errorThrown);
},
// 10. 完成回调(成功或失败都会执行)
complete: function(jqXHR, textStatus) {
console.log('请求完成', textStatus);
}
});
实战案例:用户登录接口
function login(username, password) {
return $.ajax({
url: '/api/auth/login',
type: 'POST',
contentType: 'application/json', // 告诉服务器我们发送的是JSON数据
data: JSON.stringify({
username: username,
password: password
}),
dataType: 'json',
timeout: 10000,
success: function(response) {
if (response.code === 200) {
// 保存token
localStorage.setItem('token', response.data.token);
localStorage.setItem('userInfo', JSON.stringify(response.data.user));
console.log('登录成功!欢迎', response.data.user.nickname);
// 跳转到首页
window.location.href = '/index.html';
} else {
alert('登录失败:' + response.message);
}
},
error: function(jqXHR, textStatus, errorThrown) {
console.error('登录请求失败:', textStatus);
if (jqXHR.status === 404) {
alert('登录接口不存在,请联系管理员');
} else if (jqXHR.status === 401) {
alert('用户名或密码错误');
} else if (jqXHR.status === 500) {
alert('服务器内部错误,请稍后重试');
} else {
alert('网络错误,请检查网络连接');
}
}
});
}
// 使用示例
$('#loginForm').on('submit', function(e) {
e.preventDefault();
var username = $('#username').val();
var password = $('#password').val();
// 显示加载状态
$('#loginBtn').prop('disabled', true).text('登录中...');
login(username, password).done(function() {
// 登录成功后的额外处理
console.log('登录流程完成');
}).fail(function() {
// 登录失败后的处理
$('#loginBtn').prop('disabled', false).text('登录');
});
});
实战案例:获取用户列表并分页
function getUserList(page, pageSize, keyword) {
var options = {
url: '/api/user/list',
type: 'GET',
data: {
page: page || 1,
pageSize: pageSize || 10,
keyword: keyword || ''
},
dataType: 'json',
headers: {
'Authorization': 'Bearer ' + localStorage.getItem('token')
}
};
return $.ajax(options);
}
// 渲染用户列表
function renderUserList(users) {
var html = '';
users.forEach(function(user) {
html += '<tr>';
html += '<td>' + user.id + '</td>';
html += '<td>' + user.username + '</td>';
html += '<td>' + user.email + '</td>';
html += '<td>' + (user.status === 1 ? '正常' : '禁用') + '</td>';
html += '<td>' + user.createdAt + '</td>';
html += '</tr>';
});
$('#userTableBody').html(html);
}
// 分页切换
$(document).on('click', '.page-btn', function() {
var page = $(this).data('page');
var keyword = $('#searchInput').val();
getUserList(page, 10, keyword).then(function(response) {
renderUserList(response.data.list);
renderPagination(response.data.total, page);
}).catch(function(error) {
console.error('获取用户列表失败:', error);
});
});
全局ajax设置
如果你很多请求都需要相同的配置,可以使用全局设置:
// 全局设置,所有ajax请求都会应用这些配置
$.ajaxSetup({
baseURL: 'https://api.example.com',
dataType: 'json',
timeout: 10000,
headers: {
'X-Requested-With': 'XMLHttpRequest',
'Authorization': 'Bearer ' + localStorage.getItem('token')
}
});
// 之后写ajax就简洁多了
$.ajax({
url: '/user/profile', // 实际请求 https://api.example.com/user/profile
type: 'GET',
success: function(data) {
console.log(data);
}
});
// 或者使用简写方法
$.get('/user/profile', function(data) {
console.log(data);
});
$.post('/user/save', { name: '李四' }, function(data) {
console.log(data);
});
跨域问题详解及解决方案
跨域是前端开发中另一个让人头疼的问题。浏览器的同源策略限制了不同源之间的请求,但实际开发中我们经常需要跨域访问数据。
什么是跨域?
// 当前页面:http://localhost:8080/index.html
// 以下请求都会跨域:
$.ajax({ url: 'http://localhost:8081/api/data' }); // 端口不同,跨域
$.ajax({ url: 'https://localhost:8080/api/data' }); // 协议不同,跨域
$.ajax({ url: 'http://api.example.com/data' }); // 域名不同,跨域
// 以下请求不会跨域:
$.ajax({ url: 'http://localhost:8080/api/data' }); // 同源,不跨域
$.ajax({ url: '/api/data' }); // 相对路径,同源,不跨域
解决方案一:JSONP(传统方案)
JSONP是早期解决跨域问题的经典方案,利用script标签不受同源策略限制的特性。
// 前端代码
$.ajax({
url: 'http://api.example.com/data',
dataType: 'jsonp', // 指定使用JSONP
jsonp: 'callback', // 回调函数参数名
jsonpCallback: 'handleData', // 自定义回调函数名
success: function(data) {
console.log('获取数据成功:', data);
},
error: function() {
console.error('获取数据失败');
}
});
// 定义全局回调函数
function handleData(response) {
console.log('数据:', response);
}
// 后端需要返回的数据格式:
// handleData({"code":200,"data":{"name":"张三"}});
// 注意:不是JSON格式,而是函数调用格式
解决方案二:CORS(推荐方案)
CORS(跨域资源共享)是现代浏览器支持的跨域方案,需要前后端配合。
// 前端代码 - 看起来和普通ajax一样
$.ajax({
url: 'http://api.example.com/data',
type: 'GET',
dataType: 'json',
success: function(data) {
console.log('数据:', data);
}
});
// 后端需要在响应头中添加:
// Access-Control-Allow-Origin: http://localhost:8080
// 或者允许所有来源:
// Access-Control-Allow-Origin: *
// 带凭据的请求
$.ajax({
url: 'http://api.example.com/data',
type: 'GET',
dataType: 'json',
xhrFields: {
withCredentials: true // 允许携带cookie
},
success: function(data) {
console.log('数据:', data);
}
});
// 后端需要额外设置:
// Access-Control-Allow-Origin: http://localhost:8080 // 不能是*
// Access-Control-Allow-Credentials: true
解决方案三:代理服务器(开发环境推荐)
在开发阶段,最实用的方案是配置代理服务器,把跨域请求变成同域请求。
// 使用webpack devServer代理配置(示例)
// webpack.config.js
module.exports = {
devServer: {
proxy: {
'/api': {
target: 'http://api.example.com',
changeOrigin: true,
pathRewrite: {
'^/api': '/api'
}
},
'/user': {
target: 'http://user-service.com',
changeOrigin: true
}
}
}
};
// 前端代码 - 请求代理路径
$.ajax({
url: '/api/data', // 实际请求会转发到 http://api.example.com/data
type: 'GET',
dataType: 'json',
success: function(data) {
console.log('数据:', data);
}
});
// 使用axios的proxy配置
axios.defaults.baseURL = '/api';
axios.get('/user/list').then(response => {
console.log(response.data);
});
解决方案四:Nginx反向代理(生产环境推荐)
# nginx.conf 配置
server {
listen 80;
server_name localhost;
# 前端静态资源
location / {
root /var/www/html;
index index.html;
}
# API请求代理
location /api/ {
proxy_pass http://api.example.com/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# CORS头
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, POST, PUT, DELETE, OPTIONS';
add_header Access-Control-Allow-Headers 'Content-Type, Authorization';
# 处理预检请求
if ($request_method = 'OPTIONS') {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, POST, PUT, DELETE, OPTIONS';
add_header Access-Control-Allow-Headers 'Content-Type, Authorization';
add_header Access-Control-Max-Age 86400;
add_header Content-Length 0;
return 204;
}
}
}
// 前端代码 - 生产环境也使用相对路径
$.ajax({
url: '/api/user/list', // 请求会转发到后端服务器
type: 'GET',
dataType: 'json',
success: function(data) {
console.log(data);
}
});
常见问题排查清单
当你遇到ajax问题时,按照这个清单一步步检查:
1. 检查网络请求
// 开启全局ajax错误处理
$(document).ajaxError(function(event, jqXHR, settings, thrownError) {
console.error('Ajax错误:', {
url: settings.url,
type: settings.type,
status: jqXHR.status,
statusText: jqXHR.statusText,
error: thrownError
});
});
// 开启全局ajax开始处理
$(document).ajaxStart(function() {
$('#loading').show();
});
// 开启全局ajax完成处理
$(document).ajaxComplete(function() {
$('#loading').hide();
});
2. 检查请求URL
// 打印完整URL,确认路径正确
console.log('请求URL:', settings.url);
console.log('完整URL:', window.location.origin + settings.url);
// 测试URL是否可访问
$.ajax({
url: '/api/test',
type: 'HEAD', // 只获取头信息,不获取内容
success: function() {
console.log('URL可访问');
},
error: function() {
console.log('URL不可访问或返回错误');
}
});
3. 检查请求方法
// 确认后端支持的方法
// GET - 查询
// POST - 创建
// PUT - 全量更新
// PATCH - 部分更新
// DELETE - 删除
$.ajax({
url: '/api/user/123',
type: 'DELETE', // 确保后端支持DELETE方法
success: function() {
console.log('删除成功');
}
});
4. 检查数据格式
”`javascript // 发送JSON数据 $.ajax({
url: '/api/user',
type: 'POST',
contentType: 'application/json', // 必须设置
data: JSON.stringify({
name: '张三',
age: 25
}),
success: function(data) {
console.log(data);
}
});
// 发送表单数据 $.ajax({
url: '/api/user',
type: 'POST',
contentType: 'application/x-www-form-urlencoded', // 默认值
data: {
name: '张三',
age: 25
},
success: function(data) {
console.log(data);
}
});
// 发送FormData(文件上传) var formData = new FormData(); formData.append(‘name’, ‘张三’); formData.append(‘file’, $(‘#fileInput’)[0].files[0]);
$.ajax({
