Vue2 front-end and back-end separation project ajax cross-domain session problem solving

Vue2 front-end and back-end separation project ajax cross-domain session problem solving

https://segmentfault.com/a/1190000009208644

 

Recently, I learned to use vuejs to separate the front and back ends and reconstruct an existing background management system. I encountered the following problem:

When implementing a cross-domain request, each ajax request is a new session, which makes it impossible to obtain login information, and all requests are judged as not logged in.

1. vuejs ajax cross-domain request

I used vue-resource at first, but found that vue2 recommended axios, so I changed it to axios;
install axios

npm install axios -S

After the installation is complete, add the following configuration in main.js:

import axios from 'axios';

axios.defaults.withCredentials=true;

Main.js is all configured as follows:

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')

The specific use in the XXX.vue file is as follows:

<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>

The headers that accept cross-domain access are set in the login interceptor in the background project, as follows:

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;
    }
}

Now you can access cross-domain.

2. Login session acquisition

Because it is a background management system, you must need to log in to use it, so I saved the session when I logged in.

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

I hope that when other requests come in, it will be judged in the interceptor whether I have logged in and whether I have permission to access this request path.

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

It turns out that each ajax cross-domain access is a new session, and the sessionID is different each time

A question was raised on segmentfault. Someone suggested that the ajax request should carry cookies, that is, authentication information, so in the interceptor, a header requiring authentication information was added:

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

Then I tested it in the browser again, and found that the browser prompts that when Access-Control-Allow-Credentials is set to true, Access-Control-Allow-Origin cannot be set to an asterisk. Since I am not allowed to set it as an asterisk, I Change it to the configuration of the front-end project

response.setHeader("Access-Control-Allow-Origin""http://127.0.0.1:8010");

It is found that each ajax request is still a different session, open the network of chrome, and find that the request header of each request does not contain the cookie information as I imagined, that is, the following header:

Cookie:JSESSIONID=node015f4w1j2kgjk61i7jyyim8lo3u0.node0;

Because I use axios, find the documentation link description of axios

Find out what:

  // `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 is false by default, which means that it does not carry cookie information, so let it be true. I configured it globally, which is the sentence in main.js:

axios.defaults.withCredentials=true;

Then test again and find that each ajax request is the same session (excluding the browser's options request).

3. Proxy configuration

Because I don't want to write http://127.0.0.1:8080 for every request in the page , and I use the webpack project template of element ui,
I want to use a proxy (I don't know if it is appropriate to call this):

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

Change the ajax request to the following:

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

        }).catch(function(response) {
            // 这里是处理错误的回调
            console.log(response)
        });

It is said on the Internet that it is configured as proxyTable, and the plug-in http-proxy-middleware is used. I installed the plug-in and changed it to this. Webpack always reports an error, saying that proxyTable is an illegal configuration and cannot be recognized.

I have no choice but to change to the proxy that comes with the template. It can be used and why it can be used. I don't know why proxyTabel can't be used, and I don't understand it. If you know, you can give pointers.

Although the proxy configuration is set, the request can be made normally, but it turns out that the requested session is different, and I feel so tired! ! !

No way, I can only look at whether there is a problem with the request header, and find that there are session restrictions in the returned header, as follows:

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

It is required that cookies can only be used under /xxxx, which is the root path of the project, so I changed the proxy to:

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

The session is back to normal again and can be used; I don't know why it can't be used in the form of api mapping.

This is the process of solving this cross-domain session problem, I hope it will help you a little!

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326270279&siteId=291194637