在我的VUE组件中,我使用此异步方法从API提取数据:
组件:
methods: {
async fetch() {
// console.log("##### WAIT ####");
const { data } = await staffRepository.getItems(this.teamId)
// console.log("##### END WAIT ####");
this.staffs = data
},
},
如您所见,我使用一个自定义存储库来拥有一个axios代码,该存储库已导入到我以前的组件中。
staffRepository :
export default {
getItems(nationId) {
return Repository.get(`page/${nationId}`)
},
}
最后是具有axios代码的主存储库:
存储库:
import axios from 'axios/index'
const baseDomain = 'https://my end point'
const baseURL = `${baseDomain}`
...
const headers = {
'X-CSRF-TOKEN': token,
// 'Access-Control-Allow-Origin': '*', // IF you ADD it add 'allowedHeaders' to ai server config/cors.php
'X-Requested-With': 'XMLHttpRequest',
'Content-Type': 'application/json',
Authorization: `Bearer ${jwtoken}`,
}
export default axios.create({
baseURL,
withCredentials: withCredentials,
headers: headers,
})
当jwtoken是有效且不是EXIPRED令牌时,此代码非常有用。
问题是令牌过期或找不到令牌,而我的laravel 5.8 API返回状态代码401(或其他状态)。
获取https://api.endpoint 401(未经授权)
一个好的解决方案可以在具有get方法的 staffRepository 中捕获状态代码。
MySolution :(不起作用)
getItems(nationId) {
return Repository.get(`page/${nationId}`)
.then(response => {
console.log(response)
})
.catch(error => {
console.log(error.response.status) // <-- it works!
})
},
这可能很好,因为在错误情况下,控制台中的错误为 401
但是我不能使用这种解决方案,因为我有2个嵌套的promise:这个诺言和将异步fetch()放入组件中。
如何在仍使用存储库环境的情况下修复它?
答案 0 :(得分:1)
我建议您在组件中使用返回的Promise,以使事情更明确:
methods: {
fetch() {
let data = null
staffRepository
.getItems(this.teamId)
.then(data => {
// do something with data
this.staffs = data
})
.catch(e => {
// do something with error, or tell the user
})
},
},
编辑-这将完全正常,因为如果您使用axios,则存储库中的方法将默认返回一个Promise。
尝试一下:API代码,其中HTTP是axios实例
export const get = (path: string): Promise<any> => {
return new Promise((resolve, reject) => {
HTTP.get(`${path}`)
.then((response) => {
resolve(response);
})
.catch((error) => {
reject(handleError(error));
});
});
};
// ***** Handle errors *****/
export function handleError(error) {
if (error.response) {
const status = error.response.status;
switch (status) {
case 400:
// do something
break;
case 401:
// do something, maybe log user out
break;
case 403:
break;
case 500:
// server error...
break;
default:
// handle normal errors here
}
}
return error; // Return the error message, or whatever you want to your components/vue files
}
答案 1 :(得分:1)
最佳实践解决方案是使用axios
的拦截器:
import axios from "axios";
import Cookies from "js-cookie";
export default (options = {}) => {
let client = options.client || axios.create({ baseURL: process.env.baseUrl });
let token = options.token || Cookies.get("token");
let refreshToken = options.refreshToken || Cookies.get("refreshToken");
let refreshRequest = null;
client.interceptors.request.use(
config => {
if (!token) {
return config;
}
const newConfig = {
headers: {},
...config
};
newConfig.headers.Authorization = `Bearer ${token}`;
return newConfig;
},
e => Promise.reject(e)
);
client.interceptors.response.use(
r => r,
async error => {
if (
!refreshToken ||
error.response.status !== 401 ||
error.config.retry
) {
throw error;
}
if (!refreshRequest) {
refreshRequest = client.post("/auth/refresh", {
refreshToken
});
}
const { data } = await refreshRequest;
const { token: _token, refreshToken: _refreshToken } = data.content;
token = _token;
Cookies.set("token", token);
refreshRequest = _refreshToken;
Cookies.set("refreshToken", _refreshToken);
const newRequest = {
...error.config,
retry: true
};
return client(newRequest);
}
);
return client;
};
看看client.interceptors.response.use
。另外,您应该有一个refreshToken
。我们正在拦截401
响应并发送发布请求以刷新令牌,然后等待新的 fresh 令牌并重新发送之前的请求。这是一种非常优雅且经过测试的解决方案,可以满足我公司的需求,并且也可能会满足您的需求。
要发送请求,请使用:
import api from './api'
async function me() {
try {
const res = await api().get('/auth/me')
// api().post('/auth/login', body) <--- POST
if (res.status === 200) { alert('success') }
} catch(e) {
// do whatever you want with the error
}
}
刷新令牌:刷新令牌用于生成新访问 令牌。通常,如果访问令牌具有失效日期,则一旦 过期,用户将必须再次进行身份验证才能获得访问权限 令牌。使用刷新令牌,可以跳过此步骤,并且可以请求 到API会获得一个新的访问令牌,该令牌允许用户继续 访问应用程序资源。