# Vue.js如何请求后台接口 ## 目录 1. [前言](#前言) 2. [HTTP请求基础概念](#http请求基础概念) 3. [Vue.js中常用的HTTP请求库](#vuejs中常用的http请求库) 4. [使用axios发送请求](#使用axios发送请求) 5. [使用fetch API发送请求](#使用fetch-api发送请求) 6. [请求拦截与响应拦截](#请求拦截与响应拦截) 7. [处理跨域问题](#处理跨域问题) 8. [错误处理与调试](#错误处理与调试) 9. [实战案例](#实战案例) 10. [性能优化建议](#性能优化建议) 11. [总结](#总结) ## 前言 在现代Web开发中,前后端分离已成为主流架构模式。作为前端三大框架之一,Vue.js需要通过HTTP请求与后台接口进行数据交互。本文将全面介绍Vue.js中实现HTTP请求的各种方案,从基础概念到实战应用,帮助开发者掌握高效的数据交互方法。 ## HTTP请求基础概念 ### 1. HTTP协议概述 HTTP(HyperText Transfer Protocol)是互联网上应用最广泛的网络协议,基于请求-响应模型工作。Vue.js应用通过HTTP协议与服务器交换JSON/XML格式数据。 ### 2. 常见HTTP方法 - GET:获取资源 - POST:创建资源 - PUT:更新资源 - DELETE:删除资源 - PATCH:部分更新 ### 3. HTTP状态码 - 2xx:成功(200 OK) - 3xx:重定向 - 4xx:客户端错误(404 Not Found) - 5xx:服务器错误(500 Internal Server Error) ## Vue.js中常用的HTTP请求库 ### 1. axios(推荐) Promise-based HTTP客户端,支持浏览器和Node.js环境 **优势:** - 自动转换JSON数据 - 客户端防御XSRF - 请求/响应拦截 - 取消请求 ### 2. fetch API 现代浏览器原生支持的API **特点:** - 原生支持,无需额外引入 - 基于Promise - 需要手动处理JSON转换 ### 3. vue-resource(已淘汰) Vue官方早期推出的插件,目前已停止维护 ## 使用axios发送请求 ### 1. 安装axios ```bash npm install axios # 或 yarn add axios
import axios from 'axios'; // GET请求 axios.get('/api/user?id=123') .then(response => { console.log(response.data); }) .catch(error => { console.error(error); }); // POST请求 axios.post('/api/user', { firstName: 'John', lastName: 'Doe' }) .then(response => { console.log(response.data); });
axios.defaults.baseURL = 'https://api.example.com'; axios.defaults.timeout = 5000; axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
function getUserAccount() { return axios.get('/user/12345'); } function getUserPermissions() { return axios.get('/user/12345/permissions'); } axios.all([getUserAccount(), getUserPermissions()]) .then(axios.spread(function (acct, perms) { // 两个请求都完成后执行 }));
fetch('/api/user') .then(response => { if (!response.ok) { throw new Error('Network response was not ok'); } return response.json(); }) .then(data => { console.log(data); }) .catch(error => { console.error('Error:', error); });
fetch('/api/user', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ name: 'John Doe', email: 'john@example.com' }) }) .then(response => response.json()) .then(data => { console.log('Success:', data); });
特性 | axios | fetch |
---|---|---|
浏览器支持 | 广泛(需polyfill) | 现代浏览器原生 |
请求取消 | 支持 | 通过AbortController |
JSON处理 | 自动 | 需手动.json() |
拦截器 | 支持 | 不支持 |
// 添加请求拦截器 axios.interceptors.request.use(config => { // 在发送请求前做些什么 config.headers.Authorization = localStorage.getItem('token'); return config; }, error => { // 对请求错误做些什么 return Promise.reject(error); }); // 添加响应拦截器 axios.interceptors.response.use(response => { // 对响应数据做点什么 if (response.data.code !== 200) { return Promise.reject(response.data.message); } return response.data; }, error => { // 对响应错误做点什么 if (error.response.status === 401) { router.push('/login'); } return Promise.reject(error); });
const service = axios.create({ baseURL: process.env.VUE_APP_BASE_API, timeout: 10000 }); async function request(options) { try { const response = await service(options); return response.data; } catch (error) { // 统一错误处理 if (error.response) { switch (error.response.status) { case 400: error.message = '请求错误'; break; case 401: error.message = '未授权,请登录'; break; // ...其他状态码处理 } } console.error('请求失败:', error.message); throw error; } }
浏览器同源策略限制:协议、域名、端口任一不同即产生跨域
// vue.config.js module.exports = { devServer: { proxy: { '/api': { target: 'http://localhost:3000', changeOrigin: true, pathRewrite: { '^/api': '' } } } } }
// Spring Boot示例 @Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("*") .allowedMethods("GET", "POST", "PUT", "DELETE") .maxAge(3600); } }
function jsonp(url, callbackName) { return new Promise((resolve) => { const script = document.createElement('script'); script.src = `${url}?callback=${callbackName}`; window[callbackName] = (data) => { resolve(data); document.body.removeChild(script); delete window[callbackName]; }; document.body.appendChild(script); }); }
async function fetchData() { try { const response = await axios.get('/api/data', { timeout: 5000, validateStatus: function (status) { return status >= 200 && status < 300; // 默认 } }); // 处理业务逻辑错误 if (response.data.code !== 0) { throw new Error(response.data.message); } return response.data; } catch (error) { if (axios.isCancel(error)) { console.log('请求被取消', error.message); } else if (error.response) { // 服务器响应了但状态码不在2xx范围 console.error('响应错误:', error.response.status); } else if (error.request) { // 请求已发出但没有收到响应 console.error('无响应:', error.request); } else { // 其他错误 console.error('设置请求时出错:', error.message); } // 显示用户友好的错误提示 showToast(error.message || '请求失败,请稍后重试'); throw error; // 继续抛出以供上层处理 } }
// 请求日志拦截器 axios.interceptors.request.use(config => { console.log('请求发出:', config.method.toUpperCase(), config.url); return config; }); axios.interceptors.response.use(response => { console.log('响应收到:', response.config.url, response.status); return response; });
// api/user.js export function login(username, password) { return request({ url: '/auth/login', method: 'POST', data: { username, password } }); } // 在组件中使用 import { login } from '@/api/user'; export default { methods: { async handleSubmit() { try { this.loading = true; const { token } = await login(this.form.username, this.form.password); localStorage.setItem('token', token); this.$router.push('/dashboard'); } catch (error) { this.$message.error(error.message); } finally { this.loading = false; } } } }
// api/article.js export function getArticles(params) { return request({ url: '/articles', method: 'GET', params // { page: 1, size: 10 } }); } // 在组件中使用 export default { data() { return { list: [], pagination: { page: 1, pageSize: 10, total: 0 }, loading: false }; }, methods: { async loadData() { try { this.loading = true; const { data, total } = await getArticles({ page: this.pagination.page, size: this.pagination.pageSize }); this.list = data; this.pagination.total = total; } finally { this.loading = false; } } }, created() { this.loadData(); } };
// api/upload.js export function uploadFile(file) { const formData = new FormData(); formData.append('file', file); return request({ url: '/upload', method: 'POST', data: formData, headers: { 'Content-Type': 'multipart/form-data' } }); } // 组件中使用 <input type="file" @change="handleFileChange"> methods: { async handleFileChange(event) { const file = event.target.files[0]; if (!file) return; try { const { url } = await uploadFile(file); this.$message.success(`上传成功: ${url}`); } catch (error) { this.$message.error('上传失败'); } } }
对于频繁的小请求,考虑合并为单个请求
const cache = new Map(); async function getWithCache(url) { if (cache.has(url)) { return cache.get(url); } const response = await axios.get(url); cache.set(url, response.data); return response.data; }
import { debounce } from 'lodash'; methods: { search: debounce(async function(query) { const result = await axios.get('/search', { params: { q: query } }); this.results = result.data; }, 500) }
const pendingRequests = new Map(); function addPendingRequest(config) { const key = `${config.method}-${config.url}`; config.cancelToken = new axios.CancelToken(cancel => { if (!pendingRequests.has(key)) { pendingRequests.set(key, cancel); } }); } function removePendingRequest(config) { const key = `${config.method}-${config.url}`; if (pendingRequests.has(key)) { const cancel = pendingRequests.get(key); cancel(key); pendingRequests.delete(key); } } // 在拦截器中应用 axios.interceptors.request.use(config => { removePendingRequest(config); addPendingRequest(config); return config; }); axios.interceptors.response.use(response => { removePendingRequest(response.config); return response; });
本文全面介绍了Vue.js中请求后台接口的各种方法和最佳实践。关键点总结:
随着Vue 3和Composition API的普及,HTTP请求可以进一步封装为可组合函数:
// 使用Composition API封装 import { ref } from 'vue'; import axios from 'axios'; export function useApi(url) { const data = ref(null); const error = ref(null); const loading = ref(false); async function fetch() { try { loading.value = true; const response = await axios.get(url); data.value = response.data; } catch (err) { error.value = err; } finally { loading.value = false; } } return { data, error, loading, fetch }; }
希望本文能帮助您掌握Vue.js中的HTTP请求处理,构建更高效的前端应用。 “`
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。