参考博客:
axios中Post请求变成OPTIONS的几种解决方案
一、拦截器引入前
1.首先登录:
Login.vue
axios.post(url,{
"userName":this.userName,"password":this.password}).then(response=>{
if(response.data.code==0) {
//console.log(response.data.token);window.localStorage.setItem("token",response.data.token);//路由跳转 登录成功后 跳转this.$router.replace('/phoneBook')}else {
this.errorInfo = response.data.msg;}}).catch(error=>{
this.errorInfo=error;
})
2.登录成功后跳转至电话簿列表页面:
PhoneBook.vue
export default {
name: "PhoneBook",methods: {
getPhoneBooks() {
let url = getServerUrl("phoneBook/loadAll")axios.get(url).then(response=>{
console.log(response)}).catch(error=>{
console.log(error)})}},mounted() {
this.getPhoneBooks(); //加载所有电话簿信息}}
发起loadAll请求:
/*** 查询所有电话簿信息 正常情况下要把token带过来才允许请求此方法* @return* @throws Exception*/@RequestMapping("/loadAll")public R loadAll()throws Exception{
return R.ok("电话簿信息");}
很显然,下面的请求是没有携带token的:
因此这很不合理,所以下面引入拦截器
二、拦截器的引入
1.SysInterceptor实现HandlerInterceptor接口
public class SysInterceptor implements HandlerInterceptor {
@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String contextPath = request.getRequestURI(); //完整的请求地址System.out.println("路径:"+contextPath);String token = request.getHeader("token"); //从请求中取出tokenif(handler instanceof HandlerMethod){
if(StringUtil.isEmpty(token)){
System.out.println("签名验证不存在");//即token 不存在print(response, R.error(SystemConstant.JWT_ERRCODE_NULL,"签名验证不存在"));return false;}else {
CheckResult checkResult = JwtUtils.validateJWT(token);if(checkResult.isSuccess()){
System.out.println("签名验证通过");return true;}else {
switch (checkResult.getErrCode()){
case SystemConstant.JWT_ERRCODE_FAIL:System.out.println("签名验证不通过");print(response,R.error(SystemConstant.JWT_ERRCODE_NULL,"签名验证不通过"));break;case SystemConstant.JWT_ERRCODE_EXPIRE:System.out.println("签名验证已过期");print(response,R.error(SystemConstant.JWT_ERRCODE_EXPIRE,"签名验证已过期"));break;}return false;}}}return false;}private void print(HttpServletResponse response, Object message){
try {
response.setStatus(HttpStatus.OK.value());response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);response.setHeader("Cache-Control", "no-cache, must-revalidate");PrintWriter writer = response.getWriter();writer.write(message.toString());writer.flush();writer.close();} catch (IOException e) {
e.printStackTrace();}}
}
JwtUtils在另一篇博客里面。
2.配置类里面配置拦截器
/**解决跨域问题 配置类*/
@Configuration
public class WebAppConfigurer implements WebMvcConfigurer {
@Overridepublic void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("*").allowCredentials(true).allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE","OPTIONS").maxAge(3600);}/** 这里配置把拦截器添上* 配置不需要拦截的请求* @param registry*/@Overridepublic void addInterceptors(InterceptorRegistry registry) {
String[] patterns = new String[] {
"/login","/*.html","/image"};registry.addInterceptor(new SysInterceptor()).addPathPatterns("/**").excludePathPatterns(patterns);}
}
3.首先测试,前端请求时不加token的情况
果然报错 说 签名验证不存在,因为前端发起请求时还未携带token呢!
下面 在前端请求时加上token:
export default {
name: "PhoneBook",methods: {
getPhoneBooks() {
let token = window.localStorage.getItem("token")axios.defaults.headers.common['token']=tokenlet url = getServerUrl("phoneBook/loadAll")axios.get(url).then(response=>{
console.log(response)}).catch(error=>{
console.log(error)})}},mounted() {
this.getPhoneBooks(); //加载所有电话簿信息}}
3.下面报错了,让我们一探究竟
报错一:request.getHeader(“token”); //从请求中取出token为啥是空?
报错二:if语句里面的 handler instanceof HandlerMethod 为啥是false?
三.报错原因:
原来,我们在使用axios时,遇到了Request Method: OPTIONS
每个接口都调了两次,刚开始没太注意感觉两次请求是一摸一样的,仔细看了一圈,发现第一次调用的 Request Method: OPTIONS ,第二次调用的 Request Method: GET
至于为啥调用接口两次,参考这个博客:
使用axios时遇到的Request Method: OPTIONS
下面演示:
1.点击登录后 正常取出了localStorage里面的token:
2.点击OK
然后在请求 phoneBook/loadAll 之前 下面进入了拦截器:
很明显,上图中显示的 是第一次请求的OPTIONS 我们 返回true
然后我们将此次请求放行
3.下面来到第二次请求:
继续往下走:
token终于取到了,
四、小结:
主要就是下面代码:
/* 每个接口都调了两次,刚开始没太注意感觉两次请求是一摸一样的,仔细看了一圈,发现第一次调用的 Request Method: OPTIONS ,第二次调用的 Request Method: POST或是GET 这里是GET所以下面必须加上这句 处理一下第一次请求的OPTIONS,否则我们就无法从request里面取出token了*/if(request.getMethod().equals("OPTIONS")){
response.setStatus(HttpServletResponse.SC_OK);return true;}