最近在捣鼓线上博客,没尝试过ssr
,于是使用nuxt.js
来开发,接口使用的是koa
。在nuxt
开发时遇到了几个坑(注意事项)于是记录一下:
关于asyncData
asyncData
根据官网和大部分文章的介绍,这个api
是充当在服务端调用异步接口的作用。服务端通过asyncData
调用数据之后返回数据,渲染完整个页面之后,返回给前端。这就导致了在asyncData
中我们无法使用this
来获取数据。因为this
是前端的概念,而asyncData
是在服务端。
为了请求数据我安装了@nuxtjs/axios
并根据文档,在nuxt.config.js
中进行配置:
modules: [
'@nuxtjs/axios'
],
axios: {
proxy: true,
withCredentials: true
},
作为一个有经验的工程师,肯定要给axios
做一些拦截器封装,在plugins/axios.js
中:
export default function ({ store, redirect, req, router, app: { $axios } }) {
$axios.defaults.baseURL = '/api' // 为了代理
$axios.onRequest((config) => {})
$axios.interceptors.response.use(
(response) => {
return response.data
},
(error) => {
return Promise.reject(error.response)
})
}
然后在nuxt.config.js
中进行配置:
plugins: [
'@/plugins/axios'
],
本地接口没有设置跨域这个鬼东西,于是需要本地自己配置一波:
proxy: {
'/api/': {
target: 'http://localhost:8888',
pathRewrite: {
'^/api/': '/',
changeOrigin: true
}
}
},
好了在页面的mounted
方法中调用,成功:
mounted () {
this.initData()
},
methods: {
async initData () {
// 之前有给axios设置baseURL = '/api',所以代理成功了
const res = await this.$axios.get(`/article?page=1`)
this.list= res.data
this.total= res.count
}
}
然而我试图在asyncData
这么操作时失败了:
async asyncData ({ app, params }) {
const res = await app.$axios.$get('/article?page=1')
return {
list: res.data,
total: res.count,
page: 2
}
},
renderContext.renderResourceHints is not a function
,emmm我觉得我的操作没问题,也找了好久,没发现什么BUG,于是去找了@nuxtjs/axios
官网,发现人家在asyncData
中请求地址是带了域名的,于是:
async asyncData ({ app, params }) {
const res = await app.$axios.$get('http://localhost:8888/article?page=1')
return {
list: res.data,
total: res.count,
page: 2
}
},
结果木有任何问题Orz…本真大胆推测小心求证我做了下面几件事:
- 先确保后端接口没有设置
Access-Control-Allow-Origin
; - 删除axios.baseUrl的设置;
- 设置配置文件中关于代理的配置,在
asyncData
请求带域名时,可以请求成功,但是在mounted
中请求带域名时却报了跨域问题
- 设置axios.baseUrl = ‘api’;
- 设置代理;
- 在
mounted
中使用不带域名的请求,请求成功。
所以我总结出了一个不知道对不对的道理:axios
的配置是针对前端的,所以在mounted
中baseUrl
和代理是有效的;而asyncData
是针对服务端的,所以baseUrl
和代理没有作用,且请求的时候需要使用完整的接口路径。
页面跳转和参数获取
由于详情页面的渲染也要借助asyncData
,所以获得页面路由id
时发现asyncData
只能通过params
参数获取,所以创建详情文件的时候,需要使用这样的目录:
点击列表项跳转时,需要使用:
handleClick () {
this.$router.push({
path: `/details/${this.item.id}`
})
}
所以在详情页获取接口数据时是这么写的:
async asyncData ({ params, app }) {
const res = await app.$axios.$get(`http://localhost:8888/article/details?id=${params.id}`)
return {
info: res
}
},
列表分页
首页的列表本来是做了点击按钮之后切换上下页面的,然而发现假设在第二列表页面,点击进入详情,然后返回时,又会重新触发首页的asyncData
,所以数据是第一页的数据。苍天的…
于是只能改称页面触底之后自动加载第二页,还会nuxt.js
还有点人性啊,返回来之后会自动记录上次离开的位置,所以有位置并不一定准…
点击跳转数据可以正常加载,刷新却出现了问题
这是个大坑啊,前面我们提到了,我的后台接口没有设置跨域,在使用asyncData
我使用了全程接口
首页页(列表页):
async asyncData ({ app }) {
const res = await app.$axios.$get('http://localhost:8888/article?page=1')
return {
list: res.data,
total: res.count
}
},
详情页:
async asyncData ({ params, app }) {
const res = await app.$axios.$get(`http://localhost:8888/article/details?id=${params.id}`)
return {
info: res
}
},
从首页点击跳到详情页,竟然发生了这种惨状…
刷新,我的详情页又回来了:
返回到首页:
TAT,我哭了,那么我修改一下详情页的请求,不携带域名:(这里我开了代理)
async asyncData ({ params, app }) {
const res = await app.$axios.$get(`/article/details?id=${params.id}`)
return {
info: res
}
},
然后首页跳转到详情没有问题,详情返回出首页依旧数据有问题,如果直接在详情刷新还会给一个BUG提示语…到这里我的心态已经崩了。
最后我找到了一个一劳永逸的办法,默默在我的koa
接口项目设置了跨域:
app.use(async (ctx, next) => {
ctx.set("Access-Control-Allow-Origin", "*")
await next()
})
首页和详情页都使用带有域名的接口地址,完事~
即,让后端设置一下跨域,前端直接使用完整的接口路由,不要借助代理了Orz,好了我明天去尝试一下部署到服务器上会不会有问题…
未完待续…
如有错误的地方,欢迎指出,谢谢~