2023-04-04基于nuxt3.3.3更新
nuxt3使用了ts和vue3,nuxt3的使用下来,体验还是很不错的,那么如何在nuxt3里面封装一个http请求呢
相关文档:https://nuxt.com.cn/docs/api/composables/use-fetch
新建一个http.ts
以下是基于rc.8以上版本增加了createError,错误可以在error.vue中展示
import { hash } from 'ohash'
// 后端返回的数据类型
export interface ResOptions<T> {
data: T
code?: number
message?: string
}
/**
* api请求封装
* @param { String } url 请求地址
* @param { Object } options useFtech第二个参数
* @param { Object } headers 自定义header头, 单独设置headers区分请求参数,也好设置类型
*/
const fetch = async (url: string, options?: any, headers?: any) => {
try {
// 3.0正式版环境变量要从useRuntimeConfig里的public拿
const { public: { VITE_API_HOST } } = useRuntimeConfig()
const reqUrl = VITE_API_HOST + url // 你的接口地址
// 设置key
const key = hash(JSON.stringify(options) + url)
// 可以设置默认headers例如,token的获取最好用useState返回一个useCookie
const customHeaders = { token: useToken().value, ...headers }
const { data, error } = await useFetch(reqUrl, { ...options, key, headers: customHeaders })
const result = data.value as ResOptions<any>
console.log('useFetchResData: ', result)
if (error.value || !result || (result && result.code !== 200)) {
// 处理token失效的情况
if (code === 401) {
// token.value = ''
await navigateTo('/login')
}
// 在客户端的时候抛出错误结果方便捕捉
if (process.client) {
return Promise.reject(result || error.value)
}
// 在服务端就直接渲染错误页面,需要设置一个error.vue接收错误信息
throw createError({
statusCode: 500,
statusMessage: reqUrl,
message: error.value?.message || '服务器内部错误',
})
}
return result.data // 这里直接返回data或者其他的
} catch (err) {
console.log(err)
return Promise.reject(err)
}
}
export default class Http {
get(url: string, params?: any, headers?: any) {
return fetch(url, { method: 'get', params }, headers)
}
post(url: string, body?: any, headers?: any) {
return fetch(url, { method: 'post', body }, headers)
}
put(url: string, body?: any, headers?: any) {
return fetch(url, { method: 'put', body }, headers)
}
delete(url: string, body?: any, headers?: any) {
return fetch(url, { method: 'delete', body }, headers)
}
}
新建一个api文件夹,新建一个index.ts,其他的根据业务模块新建文件,index.ts用于导出其他模块,如图:
比如我想把文章相关的api都写在一个文件里,我们可以利用到js的继承,让api代码可读性更高,例如可以在article.ts里面写:
import Http from '@/utils/http'
export default new class article extends Http {
/**
* 获取热门文章,自定义返回类型可以通过Promise<T>设置,不设置就是any
*/
public getHot(): Promise<{ items: Array<{ id: number, name: string }>}> {
return this.get('/app/v1/article/hotView')
}
/**
* 获取文章详情
* @param { Number } id 文章id
*/
public getDetail(id: number) {
return this.get('/app/v1/article/detail/' + id)
}
}
如果类型太多,可以在api里面再建一个types,里面放对应模块的.d.ts类型
api/index.ts导出这些模块:
import articleApi from '@/api/article'
export default {
articleApi,
}
composables/index.ts中:
import api from '@/api/index'
export const useApi = () => api
然后页面中使用:
<script lang="ts" setup>
const { articleApi } = useApi()
// 返回的数据结构根据自己后端在api文件定义好,这里建议直接等于返回结果,不用再去定义类型了
const hots = await articleApi.getHot({ page: 1, size: 50 })
console.log(hots.items)
</script>
类里的函数可以写成静态方法,这样就不用 new了
code === 401 这里的code是什么意思,哪里来的呀
useFetch 里面的配置选项key 好像起不来了作用,有和没有效果都一样,博主能举个例子么
用了这个封装方法,刷新页面,报错 Error: A composable that requires access to the
setup顶层处理await,你如何抛错呢?
Http是构造函数,不new就能访问里面的方法?
首屏从后台请求数据渲染以后,页面通过@绑定的事件都没有被绑定,是什么原因?你们没有出现么?用官方原始写法不会
有没有能隐藏后端请求api地址的方法
您好,使用useFetch方法去请求, 默认是混合模式(ssr、csr),部署到生产后,首次请求该页面(或是刷新后),请求都为404;但是再从其他页面跳转到此页面(此时是csr吧),请求都正常。请教您问题可能出在哪里
请问需要请求第三方服务器,怎么配置才不会跨域呢?