最近学习使用vuejs前后端分离,重构一个已有的后台管理系统,遇到了下面这个问题:

实现跨域请求时,每次ajax请求都是新的session,导致无法获取登录信息,所有的请求都被判定为未登陆。

1、 vuejs ajax跨域请求

最开始使用的是vue-resource,结果发现vue2推荐的是axios,于是改成axios;安装axios


npm           install           axios -S



安装完成后在main.js中增加一下配置:


import axios from           'axios'          ;         
          axios.defaults.withCredentials=          true          ;



main.js全部配置如下:


import Vue from           'vue'         
          import App from           './App.vue'         
          import ElementUI from           'element-ui'         
          import           'element-ui/lib/theme-default/index.css'         
          import router from           './router'          ;         
          import axios from           'axios'          ;         
          import           './assets/css/main.css'         
          import           './assets/css/color-dark.css'         
                    
          //开启debug模式         
          Vue.config.debug =           true          ;         
          axios.defaults.withCredentials=          true          ;         
          Vue.prototype.$axios = axios;         
          Vue.use(ElementUI);         
                    
          new           Vue(         
                    {         
                    router,         
                    el:           '#app'          ,         
                    render: h => h(App)         
                    }         
          ).$mount(          '#app'          )



在XXX.vue文件中具体使用如下:


<template>         
                    
                    <el-col :span=          "4"           style=          "background-color: #eef1f6;height:100%;"          >         
                    <el-menu           default          -active=          "1"           class=          "el-menu-vertical-demo"           :unique-opened=          "uniqueOpened"           router         
                    v-          for          =          "menu in menulist"           :key=          "menu.fidStr"          >         
                    <template v-          if          =          "menu.isleaf === 1"          >         
                    <el-menu-item :index=          "menu.furl"          >{{menu.fname}}</el-menu-item>         
                    </template>         
                    <template v-          else          >         
                    <el-submenu :index=          "menu.fidStr"          >         
                    <template slot=          "title"          ><i class=          "el-icon-menu"          ></i>{{menu.fname}}</template>         
                    <template v-          for          =          "firstLevelChild in menu.children"           >         
                    <template v-          if          =          "firstLevelChild.isleaf === 1"           >         
                    <el-menu-item :index=          "firstLevelChild.furl"          >{{firstLevelChild.fname}}</el-menu-item>         
                    </template>         
                    <template v-          else          >         
                    <el-submenu :index=          "firstLevelChild.fidStr"          >         
                    <template slot=          "title"          ><i class=          "el-icon-menu"          ></i>{{firstLevelChild.fname}}</template>         
                    <el-menu-item v-          for          =          "secondLevelChild in firstLevelChild.children"           :index=          "secondLevelChild.furl"          >         
                    {{secondLevelChild.fname}}         
                    </el-menu-item>         
                    </el-submenu>         
                    </template>         
                    </template>         
                    </el-submenu>         
                    </template>         
                    </el-menu>         
                    
                    </el-col>         
                    
          </template>         
                    
          <script type=          "text/javascript"          >         
                    
          export           default           {         
                    data() {         
                    return           {         
                    uniqueOpened:          true          ,         
                    menulist:[]         
                    }         
                    }   ,         
                    mounted:           function          () {         
                    let self =           this          ;         
                    this          .$axios.post(          'http://localhost:8080/test/xxx/xxxx'          , {}, {         
                    headers: {         
                    "Content-Type"          :          "application/json;charset=utf-8"         
                    },         
                    withCredentials :           true         
                    }).then(          function          (response) {         
                    // 这里是处理正确的回调         
                    let result = response.data.result;         
                    if           (0 == result) {         
                    self.menulist = response.data.item.menulist;         
                    }           else           if           (11 == result || 9 == result) {         
                    self.$router.push(          '/login'          );         
                    }           else           {         
                    console.log(response.data);         
                    }         
                    
                    }).          catch          (           function          (response) {         
                    // 这里是处理错误的回调         
                    console.log(response)         
                    });         
                    }         
                    }         
                    
          </script>         
                    
          <style scoped>         
                    .sidebar{         
                    display: block;         
                    position: absolute;         
                    width: 200px;         
                    left: 0;         
                    top: 70px;         
                    bottom:0;         
                    background:           #2E363F;         
                    }         
                    .sidebar > ul {         
                    height:100%;         
                    }         
          </style>



在后台项目中的登陆拦截器中设置了,接受跨域访问的header,如下:


public class LoginInterceptor extends HandlerInterceptorAdapter {         
                    
                    @Override         
                    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)         
                    throws Exception {         
                    
                    response.setHeader(          "Access-Control-Allow-Headers"          ,           "X-Requested-With, accept, content-type, xxxx"          );         
                    response.setHeader(          "Access-Control-Allow-Methods"          ,           "GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH"          );         
                    response.setHeader(          "Access-Control-Allow-Origin"          ,           "*"          );          
                    
                    
                    return           true          ;         
                    }         
          }



现在可以就可以跨域访问了。

2、登陆session获取

因为是后台管理系统,肯定都需要需要登陆,才能用的, 因此我在登陆时保存了session


//登陆成功         
          session.setAttribute(          "user"          , obj);



我希望其它请求进来时,在拦截器中判断是否登陆了,是否有权限访问这个请求路径


//拦截器中增加,获取session代码         
          HttpSession session =request.getSession();         
          System.out.println(          "拦截器中的session的id是===="           + session.getId());         
          Object obj = session.getAttribute(          "user"          );



结果发现,每次ajax跨域访问都是新的session ,每次的sessionID都不一样

在segmentfault上提了一个问题,有人提示需要让ajax请求携带cookie,也就是认证信息,于是在拦截器中,增加了一个需要认证信息的header:


response.setHeader(          "Access-Control-Allow-Credentials"          ,           "true"          );



然后再次在浏览器中测试,发现浏览器提示,当Access-Control-Allow-Credentials设为true的时候,Access-Control-Allow-Origin不能设为星号,既然不让我设为星号,我就改成前端项目的配置


response.setHeader(          "Access-Control-Allow-Origin"          , <a href=          "http://127.0.0.1:8010"           rel=          "external nofollow"          >http://127.0.0.1:8010</a>);



发现每次ajax请求,还是不同的session,打开chrome的network,发现每次请求的请求头中并没有,和我想象的一样携带cookie信息,也就是下面这个header:


Cookie:JSESSIONID=node015f4w1j2kgjk61i7jyyim8lo3u0.node0;



因为我用的axios,所以找到axios的文档链接描述

发现一下内容:


// `timeout` specifies the number of milliseconds before the request times out.         
          // If the request takes longer than `timeout`, the request will be aborted.         
          timeout: 1000,         
                    
          // `withCredentials` indicates whether or not cross-site Access-Control requests         
          // should be made using credentials         
          withCredentials: false, // default         
                    
          // `adapter` allows custom handling of requests which makes testing easier.         
          // Return a promise and supply a valid response (see lib/adapters/README.md).         
          adapter: function (config) {         
                    /* ... */         
          },



withCredentials默认是false,意思就是不携带cookie信息,那就让它为true,我是全局性配置的,就是main.js中的这句话:


axios.defaults.withCredentials=          true          ;



然后再测试,发现每次ajax请求都是同样的session了(不包含浏览器的options请求)。

3、代理配置

因为不想每个页面里的请求都写http://127.0.0.1:8080,并且我用的是element ui的webpack项目模板,所以就想使用代理(不知道叫这个合适不合适):


devServer: {         
                    host:           '127.0.0.1'          ,         
                    port: 8010,         
                    proxy: {         
                    '/api/'          : {         
                    target:           'http://127.0.0.1:8080'          ,         
                    changeOrigin:           true          ,         
                    pathRewrite:{         
                    '/api'          :          '/xxxxxx'         
                    }         
                    }         
                    }



把ajax请求改成下面这个样子:


this          .$axios.post(          '/api/xx/xxx'          , {}, {         
                    headers: {         
                    "Content-Type"          :           "application/json;charset=utf-8"         
                    }              
                    }).then(          function          (response) {         
                    // 这里是处理正确的回调              
                    
                    }).          catch          (          function          (response) {         
                    // 这里是处理错误的回调         
                    console.log(response)         
                    });



网上说都是配置为proxyTable, 用的是http-proxy-middleware这个插件,我装上插件,改成这个,webpack总是报错,说proxyTable是非法的配置,无法识别。

无奈改成了模板自带的proxy,可以使用,为什么可以用,我还不请求,proxyTabel为什么不能用,也没搞明白。有知道的,可以指点一下。

虽然代理配置好了,也能正常请求,结果发现请求的session又不一样了,感觉心好累啊!!!

没办法,只能再看请求头是不是有问题,发现返回header中有session限制的,如下:


复制代码代码如下:



set-cookie:JSESSIONID=node0v5dmueoc119rb42b59k5qf3w0.node0;Path=/xxxx



要求cookie只能再/xxxx下也就是项目的根路径下使用,于是我把代理改成:


devServer: {         
                    host:           '127.0.0.1'          ,         
                    port: 8010,         
                    proxy: {         
                    '/xxxx/'          : {         
                    target:           'http://127.0.0.1:8080'          ,         
                    changeOrigin:           true         
                    }         
                    }



session又恢复正常了,可以用了;不知道为什么配成api映射的形式为什么不能用。

这就是解决这个跨域session问题的过程,希望对大家有点帮助!