前端开发里,和后端接口打交道是绕不开的事儿,而axios作为当下热门的HTTP请求工具,和Web API的对接更是核心环节,你是不是也遇到过“请求发出去了但没数据”“跨域报错一头雾水”“token加了还是没权限”这些问题?这篇文章就用问答思路,把axios对接Web API的门道拆明白,从基础到实战,再到踩坑解决,帮你把数据交互这事儿理顺!
很多刚入门的同学会疑惑:axios是干啥的?Web API又是什么?简单说,axios是个能在浏览器和Node.js里发HTTP请求的工具,基于Promise设计,写代码时链式调用或者async/await都很顺手,而Web API是后端开发同学提供的“数据接口”,比如你做电商项目,获取商品列表、下单这些功能,后端会暴露对应的API地址(像/api/goods、/api/order),前端通过请求这些地址来拿数据或者提交数据。
举个生活例子:你去奶茶店点单(前端发请求),菜单就是Web API里的“接口列表”(哪些能点),店员接收你的订单并和后厨沟通(后端处理请求),最后把奶茶给你(返回响应),axios就像是你和店员沟通的“语言工具”,让这个过程更顺畅。
为啥选axios对接Web API?它有几个硬优势:一是自动把响应数据转成JSON,不用自己手动parse;二是能设置请求拦截器、响应拦截器,统一处理token、loading这些逻辑;三是对请求取消、超时控制这些细节支持得很友好,比起原生fetch或者XMLHttpRequest,写代码效率高太多。
axios对接Web API的核心步骤是啥?
想让axios和Web API“打通”,得按步骤来,每一步都有讲究:
把axios引进项目里
如果是Vue、React这类前端框架项目,一般用npm安装:npm install axios,然后在需要的文件里引入:import axios from 'axios';,要是纯静态页面,用CDN更方便:<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>,这样全局就有axios对象了。
配置基础信息,减少重复代码
每个Web API都有固定的基础地址,比如后端接口统一是https://api.myblog.com/v1开头,那可以给axios设置baseURL,以后发请求就不用每次写完整地址,还能设置超时时间(比如5秒没响应就报错)、请求头(比如默认加Content-Type),代码长这样:
const request = axios.create({
baseURL: 'https://api.myblog.com/v1', // 后端API的基础地址
timeout: 5000, // 超时时间,单位毫秒
headers: { 'Content-Type': 'application/json' } // 默认请求头
});这样创建的request实例,后续发请求更简洁,还能给不同模块(比如用户模块、文章模块)创建不同实例,管理更灵活。
发起基本请求:GET、POST怎么用?
Web API最常用的就是GET(查数据)、POST(提交数据)这些请求方式,用axios写起来很直观:
GET请求(拿数据):比如获取文章列表,后端接口是
/articles,还能传页码参数,用axios的话:
// 方式一:params传参
request.get('/articles', {
params: { page: 1, size: 10 } // 会自动拼到url后面变成?page=1&size=10
}).then(res => {
console.log('文章列表', res.data); // res.data是后端返回的实际数据
}).catch(err => {
console.error('请求失败', err);
});
// 方式二:async/await(更简洁)
async function getArticles() {
try {
const res = await request.get('/articles', { params: { page: 1 } });
return res.data;
} catch (err) {
// 处理错误
}
}POST请求(提交数据):比如用户注册,后端接口是
/users/register,需要传用户名、密码,代码:
const userInfo = { username: '小明', password: '123456' };
request.post('/users/register', userInfo)
.then(res => {
console.log('注册成功', res.data);
})
.catch(err => {
if (err.response) {
// 后端返回了错误状态码,比如400(参数错)、500(服务器炸了)
console.log('后端返回错误:', err.response.data.msg);
} else {
// 网络问题,比如断网、超时
console.log('网络请求失败');
}
});这里要注意,POST请求的第二个参数是请求体(body),axios会根据请求头自动处理格式,如果是表单提交(Content-Type是application/x-www-form-urlencoded),得用qs库把对象转成键值对格式,
import qs from 'qs';
const userInfo = { username: '小明', password: '123456' };
request.post('/users/login', qs.stringify(userInfo), {
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
});响应和错误怎么处理更稳?
后端返回的数据里,一般会有状态码(比如200成功,401没权限,500服务器错)和数据体,axios的响应对象res里,res.data才是后端真正返回的业务数据,res.status是HTTP状态码,res.headers是响应头。
错误处理分两种情况:一是请求发出去了但后端返回错误状态码(比如400、404),这时err.response存在;二是请求没发出去(比如网络断了、超时),这时err.response是undefined,所以catch里要分情况处理:
async function fetchData() {
try {
const res = await request.get('/some-api');
// 成功,处理res.data
} catch (err) {
if (err.response) {
// 后端返回错误
const { status, data } = err.response;
if (status === 401) {
// 没权限,跳登录页
window.location.href = '/login';
} else if (status === 400) {
alert('参数错误:' + data.msg);
}
} else {
// 网络或超时错误
alert('请检查网络连接');
}
}
}对接时最容易踩的坑,咋解决?
很多同学跟着步骤做还是会报错,这部分把高频问题拎出来,教你怎么破:
跨域报错:No 'Access-Control-Allow-Origin' header...
这是浏览器的同源策略搞的鬼(协议、域名、端口有一个不一样就算跨域),解决得前后端配合:
后端配置CORS:后端在响应头里加
Access-Control-Allow-Origin: *(开发时可以,生产要限制域名),还要允许对应的请求方法(GET、POST等)和请求头,比如Node.js的Express框架,装cors中间件:npm install cors,然后用:
const cors = require('cors');
app.use(cors());前端开发时用代理:比如Vue项目,在
vue.config.js里配置devServer.proxy,把前端请求代理到后端域名,假装是同源请求:
module.exports = {
devServer: {
proxy: {
'/api': {
target: 'https://api.myblog.com', // 后端真实地址
changeOrigin: true, // 开启代理
pathRewrite: { '^/api': '' } // 把请求里的/api替换成空
}
}
}
};这样前端发请求到/api/articles,会被代理到https://api.myblog.com/articles,绕开跨域限制。
多次请求重复,数据覆盖(竞态问题)
比如用户快速点“刷新列表”按钮,多次发GET请求,后发的请求先返回,导致界面显示旧数据,解决用axios的取消请求功能:
let cancelToken = null;
async function refreshList() {
// 每次请求前,取消上一次的请求
if (cancelToken) {
cancelToken.cancel('请求被取消');
}
cancelToken = axios.CancelToken.source(); // 创建新的取消令牌
try {
const res = await request.get('/articles', {
cancelToken: cancelToken.token
});
// 处理数据
} catch (err) {
if (axios.isCancel(err)) {
console.log('请求被取消', err.message);
} else {
// 其他错误处理
}
}
}token失效或权限不足(401错误)
后端一般用token做身份验证,请求时要把token放到请求头里,可以用**请求拦截器**统一加token:
request.interceptors.request.use(config => {
const token = localStorage.getItem('token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
}, err => {
return Promise.reject(err);
});然后用**响应拦截器**处理401错误(比如token过期,跳登录页):
request.interceptors.response.use(res => {
return res;
}, err => {
if (err.response && err.response.status === 401) {
// 清除过期token
localStorage.removeItem('token');
// 跳转到登录页
window.location.href = '/login';
}
return Promise.reject(err);
});数据格式不对,后端收不到或前端解析错
比如前端发POST请求,后端期望form-data格式,但前端用了json格式,就会解析失败,这时候要检查请求头和数据格式:
发form-data:用FormData对象,或者qs库转成键值对,同时设置请求头:
const formData = new FormData();
formData.append('username', '小明');
formData.append('avatar', file); // 上传文件时用FormData更方便
request.post('/users/upload', formData, {
headers: { 'Content-Type': 'multipart/form-data' }
});后端返回非JSON格式:比如返回纯文本,axios默认会尝试转JSON导致报错,这时候在请求配置里加
responseType: 'text':
request.get('/api/text', {
responseType: 'text'
}).then(res => {
console.log(res.data); // 现在是纯文本
});实战:用axios对接RESTful Web API做个博客系统
光说不练假把式,现在模拟一个博客系统的核心功能,看axios怎么和Web API配合:
场景:用户登录 + 获取文章列表 + 发布文章
配置axios实例(统一管理基础地址、token)
import axios from 'axios';
// 创建带配置的axios实例
const api = axios.create({
baseURL: 'https://api.blogdemo.com/v1',
timeout: 6000,
headers: { 'Content-Type': 'application/json' }
});
// 请求拦截器:加token
api.interceptors.request.use(config => {
const token = localStorage.getItem('blog_token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});
// 响应拦截器:处理401
api.interceptors.response.use(res => res, err => {
if (err.response?.status === 401) {
localStorage.removeItem('blog_token');
window.location.href = '/login.html';
}
return Promise.reject(err);
});
export default api;用户登录功能(POST请求)
import api from './api';
// 登录函数
export async function login(user) {
try {
const res = await api.post('/auth/login', user);
// 登录成功,存token
localStorage.setItem('blog_token', res.data.token);
return res.data; // 返回用户信息
} catch (err) {
if (err.response) {
// 后端返回错误,比如账号密码错
return { code: err.response.status, msg: err.response.data.msg };
} else {
return { code: 500, msg: '网络连接失败' };
}
}
}
// 调用登录
const user = { username: 'test', password: '123' };
login(user).then(res => {
if (res.code === 200) {
alert('登录成功');
} else {
alert(res.msg);
}
});获取文章列表(GET请求,带参数)
export async function getArticleList(page = 1) {
try {
const res = await api.get('/articles', {
params: { page, size: 10 }
});
return res.data.list; // 假设后端返回{ list: [...], total: 100 }
} catch (err) {
console.error('获取文章列表失败', err);
return [];
}
}
// 调用
getArticleList(1).then(list => {
if (list.length) {
// 渲染到页面
renderArticles(list);
} else {
alert('暂无文章');
}
});发布文章(POST请求,带token)
export async function publishArticle(data) {
try {
const res = await api.post('/articles', data);
return res.data; // 后端返回文章ID等信息
} catch (err) {
if (err.response) {
return { code: err.response.status, msg: err.response.data.msg };
} else {
return { code: 500, msg: '发布失败,请检查网络' };
}
}
}
// 调用:假设data是{ title: '我的第一篇博客', content: '正文...' }
const articleData = { title: '测试', content: '内容' };
publishArticle(articleData).then(res => {
if (res.code === 200) {
alert('发布成功,文章ID:' + res.data.id);
} else {
alert(res.msg);
}
});这个实战案例里,能看到axios实例的配置、拦截器的作用、不同请求的写法,还有错误处理的细节,实际项目中,还可以把这些函数封装到Vuex的action里,或者React的hooks中,让组件更简洁。
进阶:让axios对接更高效的技巧
把基础流程跑通后,还要优化体验和代码质量,这些技巧能帮你更上一层楼:
拦截器玩出花:统一处理loading、错误提示
很多项目里,发请求时要显示loading,请求结束后隐藏,用请求拦截器和响应拦截器统一处理:
// 全局loading(假设用element-ui的Loading组件)
import { Loading } from 'element-ui';
let loadingInstance = null;
// 请求拦截器:显示loading
api.interceptors.request.use(config => {
loadingInstance = Loading.service({ fullscreen: true });
return config;
}, err => {
loadingInstance.close();
return Promise.reject(err);
});
// 响应拦截器:隐藏loading
api.interceptors.response.use(res => {
loadingInstance.close();
return res;
}, err => {
loadingInstance.close();
if (err.response?.status === 401) {
// 之前的处理
}
return Promise.reject(err);
});这样所有请求都会自动显示loading,不用每个请求都写重复代码。
封装请求工具:减少重复,提高可维护性
把常用的GET、POST、PUT、DELETE封装


网友回答文明上网理性发言 已有0人参与
发表评论: