Code前端首页关于Code前端联系我们

1.fetch 是啥?在 Vue2 里主要用来做什么?

terry 3小时前 阅读数 6 #Vue
文章标签 Vue2fetch

在 Vue2 项目里,很多同学会纠结“该用 axios 还是 fetch 发请求”,也常碰到 fetch 报错不知咋处理、想加拦截器没思路这些问题,这篇文章用问答形式,把 Vue2 结合 fetch 开发时的关键知识点、避坑技巧讲透,帮你搞懂 fetch 在 Vue2 里的用法逻辑~

fetch 是**浏览器原生的网络请求 API**,基于 Promise 设计,能让我们在前端发起 HTTP 请求(像 GET、POST 这些),从后端接口拿数据或者提交数据,在 Vue2 项目里,它的核心作用和 axios 类似——给组件、Vuex 等模块提供“和后端交互”的能力,比如页面初始化时拉取列表数据、表单提交时把用户输入发过去。

和 axios 最大的区别是:axios 是第三方封装库(得 npm 安装),而 fetch 是浏览器自带的,不用额外装依赖,fetch 本身是“底层 API”,不像 axios 那样把很多常用功能封装好(比如自动处理响应 JSON、拦截器、取消请求这些),所以用的时候得自己写不少逻辑。

Vue2 里用 fetch 发 GET 请求,代码咋写?

最基础的场景是“组件创建时拉取列表数据”,步骤分 3 步:发起请求 → 解析响应 → 把数据存到组件 data 里,直接看代码示例(假设要请求商品列表接口):

<template>
  <div>
    <ul>
      <li v-for="item in goodsList" :key="item.id">{{ item.name }}</li>
    </ul>
  </div>
</template>
<script>
export default {
  data() {
    return {
      goodsList: [] // 用来存接口返回的商品列表
    }
  },
  created() { // 组件创建后就发请求
    // 1. 发起 GET 请求(默认就是 GET,options 可以省略)
    fetch('https://api.example.com/goods') 
      // 2. 解析响应:response.json() 会把响应体转成 JSON 对象(注意这步是异步的)
      .then(response => response.json()) 
      // 3. 把数据赋值给 data
      .then(data => {
        this.goodsList = data
      })
      // 4. 捕获错误(比如网络断了、接口 404 这些情况)
      .catch(error => {
        console.error('获取商品列表失败:', error)
        // 也可以给用户提示,this.$message.error('加载失败~')
      })
  }
}
</script>

这里要注意两个细节:

  • response.json()异步操作(因为响应体可能很大,浏览器要慢慢读),所以必须用 .then 处理,如果接口返回的不是合法 JSON 格式,这一步会报错,要在 catch 里处理。
  • fetch 对“状态码非 2xx”的情况(404、500)不会直接 reject,得自己判断 response.ok,比如接口返回 404 时,response.okfalse,但 fetch 不会进 catch,得手动抛错:
fetch(...)
  .then(response => {
    if (!response.ok) { 
      // 状态码不是 2xx,主动抛错,让错误进到 catch 里
      throw new Error(`请求失败,状态码:${response.status}`) 
    }
    return response.json()
  })
  .then(...)
  .catch(...)

用 fetch 发 POST 请求,带参数咋处理?

POST 请求分两种常见场景:传 JSON 格式数据(比如提交表单)、传 FormData 格式数据(比如上传文件),写法不一样,一个个说。

场景 1:传 JSON 格式数据

要给请求头加 Content-Type: application/json,并且把参数用 JSON.stringify 转成字符串,示例:提交用户注册信息

methods: {
  async submitRegister() {
    const userData = {
      username: this.username,
      password: this.password,
      email: this.email
    }
    try {
      const response = await fetch('https://api.example.com/register', {
        method: 'POST', // 指定请求方法是 POST
        headers: {
          'Content-Type': 'application/json' // 告诉后端传的是 JSON
        },
        body: JSON.stringify(userData) // 把对象转成 JSON 字符串
      })
      if (!response.ok) {
        throw new Error('注册失败,请检查参数~')
      }
      const resData = await response.json()
      console.log('注册成功,返回数据:', resData)
      // 比如跳转到登录页:this.$router.push('/login')
    } catch (error) {
      console.error('注册出错:', error)
      // 给用户提示:this.$message.error(error.message)
    }
  }
}

场景 2:传 FormData 格式数据(比如上传文件)

这种情况不用手动设置 Content-Type,浏览器会自动加 multipart/form-data,示例:上传用户头像

methods: {
  handleFileChange(e) {
    const file = e.target.files[0]
    if (!file) return
    const formData = new FormData()
    formData.append('avatar', file) // 第一个参数是后端要的字段名,第二个是文件
    formData.append('username', this.username) // 还能传其他参数,比如用户名
    fetch('https://api.example.com/upload', {
      method: 'POST',
      body: formData // 直接把 FormData 实例丢进去
    })
    .then(response => {
      if (!response.ok) throw new Error('上传失败')
      return response.json()
    })
    .then(data => {
      console.log('上传成功,头像地址:', data.avatarUrl)
      this.avatar = data.avatarUrl // 把返回的头像地址赋值给页面
    })
    .catch(error => {
      console.error('上传错误:', error)
    })
  }
}

fetch 和 axios 在 Vue2 项目里该怎么选?

很多同学纠结“用哪个更方便”,得看项目需求和场景,先对比核心差异:

维度 fetch(原生 API) axios(第三方库)
是否需安装 不需要(浏览器自带) 需要 npm install axios 安装
错误处理 4xx/5xx 不会自动 reject,需手动判 response.ok 状态码非 2xx 会自动 reject
响应处理 需手动 response.json() 转 JSON 自动把响应转成 JSON(除非配置了其他格式)
拦截器 没有内置拦截器,需自己封装 内置请求拦截器、响应拦截器
取消请求 需用 AbortController 手动实现 内置 cancelToken 方便取消
浏览器兼容 IE 完全不支持,移动端需看版本(如 Android 4.4+) 兼容 IE(需配 polyfill),移动端友好

选择建议

  • 小项目、快速原型开发:用 fetch,不用额外装依赖,代码轻量。
  • 中大型项目、需要拦截器(比如统一加 token、统一处理错误)、需要兼容旧浏览器、需要方便取消请求:选 axios,能省很多自己封装的工作量。

想给 fetch 加“请求拦截”“响应拦截”,咋实现?

axios 内置了拦截器,fetch 没有,得自己封装一个“请求工具函数”来模拟拦截逻辑,核心思路是:在发请求前统一处理参数(比如加 token),在响应返回后统一处理错误(token 过期跳登录)

示例:封装一个 fetchWrapper 函数,同时实现请求拦截和响应拦截

// 假设项目里有 router(Vue Router),用来跳转页面
import router from '@/router' 
// 封装后的 fetch 工具函数
function fetchWrapper(url, options = {}) {
  // —— 请求拦截逻辑 ——
  // 1. 加公共请求头(token)
  const token = localStorage.getItem('token') // 从 localStorage 拿 token
  const defaultHeaders = {
    'Authorization': `Bearer ${token}`, // 假设后端用 Bearer token 鉴权
    'Content-Type': 'application/json' // 也可以加其他公共头
  }
  // 合并用户传的 headers 和公共 headers(用户传的优先级更高)
  options.headers = { ...defaultHeaders, ...options.headers }
  // 2. 其他请求前操作:比如加载中动画(如果有全局 loading 组件)
  // this.$loading.show() —— 注意:这里不能直接用 this,得想其他方式管理 loading,Vuex
  // —— 发起请求 ——
  return fetch(url, options)
    .then(response => {
      // —— 响应拦截逻辑 ——
      // 1. 处理通用错误(token 过期,状态码 401)
      if (response.status === 401) { 
        // 跳转到登录页,并且清除无效 token
        localStorage.removeItem('token')
        router.push('/login')
        throw new Error('登录状态失效,请重新登录~')
      }
      // 2. 处理其他状态码错误(500 服务器错误)
      if (!response.ok) {
        throw new Error(`请求失败,状态码:${response.status}`)
      }
      return response
    })
    .then(response => {
      // 把响应转成 JSON(如果接口返回 JSON 的话)
      return response.json()
    })
    .catch(error => {
      // 全局错误捕获:比如弹 Toast 提示用户
      console.error('请求出错:', error)
      // this.$message.error(error.message) —— 同样,这里要考虑怎么全局调用
      throw error // 把错误抛出去,让调用方也能 catch
    })
}
// —— 在组件里使用封装后的 fetchWrapper ——
export default {
  created() {
    fetchWrapper('https://api.example.com/user')
      .then(data => {
        console.log('用户信息:', data)
      })
      .catch(error => {
        // 这里也能捕获错误
      })
  }
}

这样封装后,所有请求都会自动加 token、自动处理 401 跳转、自动解析 JSON,和 axios 的拦截器逻辑就很像了~

Vue2 里用 fetch 处理异步,咋和 async/await 结合?

fetch 本身返回 Promise,所以可以用 async/await 让代码更像“同步写法”,结构更清晰,核心是用 try...catch 捕获错误,代替 .then().catch() 链式调用。

示例:在组件 created 钩子拉取用户信息

export default {
  data() {
    return {
      userInfo: {}
    }
  },
  async created() { // 注意这里要加 async
    try {
      // 发起请求(await 等待请求完成)
      const response = await fetch('https://api.example.com/user')
      // 判断响应是否成功
      if (!response.ok) {
        throw new Error('获取用户信息失败')
      }
      // 解析响应体(await 等待解析完成)
      const data = await response.json()
      // 赋值给 data
      this.userInfo = data
    } catch (error) {
      // 捕获所有错误:网络问题、状态码错误、解析错误等
      console.error('获取用户信息出错:', error)
      // 给用户提示:this.$message.error('加载用户信息失败~')
    }
  }
}

这种写法的好处是:代码层级更少,逻辑更直观,尤其是多个请求有依赖关系时(比如先拿用户 ID,再拿用户详情),用 async/await 嵌套更清晰。

fetch 常见错误咋处理?有哪些典型场景?

fetch 踩坑最多的就是“错误不自动捕获”“跨域”“解析失败”这些问题,得针对性处理:

场景 1:网络问题(比如断网)

当用户设备没网时,fetch 会直接 reject,错误会进到 catch 里,可以在 catch 里提示用户检查网络:

.catch(error => {
  if (error.message.includes('Failed to fetch')) { 
    // 这种情况一般是网络问题
    console.error('网络好像断了~请检查网络设置')
  } else {
    console.error('其他错误:', error)
  }
})

场景 2:响应状态码非 2xx(404、500)

前面提过,fetch 不会自动把这些状态码当错误,得手动判 response.ok,可以在解析响应前抛错:

fetch(...)
  .then(response => {
    if (!response.ok) {
      // 把状态码和响应内容一起抛出去,方便调试
      return response.text().then(text => {
        throw new Error(`状态码${response.status},响应内容:${text}`)
      })
    }
    return response.json()
  })
  .catch(...)

场景 3:跨域问题(CORS)

如果后端接口没配置 CORS(跨域资源共享),浏览器会直接拦截响应,fetch 会报错,这种情况前端改不了,得让后端同学在响应头加:

Access-Control-Allow-Origin: * // 或者指定前端域名
Access-Control-Allow-Methods: GET, POST, PUT, DELETE // 允许的请求方法
Access-Control-Allow-Headers: Content-Type, Authorization // 允许的请求头

开发阶段可以用 Vue2 的代理解决跨域(配置 vue.config.js):

// vue.config.js
module.exports = {
  devServer: {
    proxy: {
      '/api': { // 把以 /api 开头的请求代理到目标域名
        target: 'https://api.example.com', 
        changeOrigin: true, // 开启跨域
        pathRewrite: { '^/api': '' } // 去掉请求路径里的 /api
      }
    }
  }
}
// 组件里请求时,把 url 改成 /api/xxx
fetch('/api/goods') 

场景 4:响应解析失败(比如接口返回非 JSON 格式)

如果接口返回的不是 JSON(比如返回 HTML、纯文本),用 response.json() 会报错,可以先用 response.text() 看内容,再处理:

fetch(...)
  .then(response => {
    if (!response.ok) { ... }
    // 先转成文本,判断是否是 JSON
    return response.text().then(text => {
      try {
        return JSON.parse(text) // 尝试转 JSON
      } catch (parseError) {
        return text // 转不了,返回原文本
      }
    })
  })
  .then(data => {
    console.log('响应数据:', data)
  })
  .catch(...)

Vue2 结合 Vuex 时,fetch 咋管理异步数据?

Vuex 是 Vue2 里的状态管理工具,用 fetch 从接口拿数据后,要把数据存到 Vuex 的 state 里,步骤是:在 action 里发请求 → 提交 mutation 改 state

示例:用 fetch 拉取用户信息并存到 Vuex

第一步:写 Vuex 模块(user.js)

// src/store/modules/user.js
const state = {
  userInfo: {} // 存用户信息
}
const mutations = {
  // 定义修改 userInfo 的 mutation
  SET_USER_INFO(state, payload) {
    state.userInfo = payload
  }
}
const actions = {
  // 定义异步 action,用 fetch 拉取数据
  async fetchUserInfo({ commit }) {
    try {
      const response = await fetch('https://api.example.com/user')
      if (!response.ok) {
        throw new Error('获取用户信息失败')
      }
      const data = await response.json()
      // 提交 mutation,把数据存到 state
      commit('SET_USER_INFO', data)
    } catch (error) {
      console.error('fetchUserInfo 出错:', error)
      // 可以 dispatch 其他 action 处理错误,比如记录日志
    }
  }
}
export default {
  namespaced: true, // 开启命名空间,避免模块间冲突
  state,
  mutations,
  actions
}

第二步:在组件里触发 action

<template>
  <div>
    <p>用户名:{{ userInfo.username }}</p>
    <p>邮箱:{{ userInfo.email }}</p>
  </div>
</template>
<script>
import { mapState } from 'vuex'
export default {
  computed: {
    // 从 Vuex 的 user

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门