axios跨域请求Java后台出现后台session为空问题

最近在做一个前后端分离的项目,前端使用React+Ant,后端是Spring mvc+mybatis+mysql,第一次做前后端分离的项目,又第一次用React+Ant,对于一直做后端的我来说,前端各种问题不断,项目时间又急,真是无比煎熬,但是又很享受在解决问题之后的喜悦。
问题描述:登录的时候前台axios跨域请求访问在java后台生成验证码并放到session中

/*
* 生成验证码
 */
@RequestMapping(value="/getVerifyCode",method={RequestMethod.POST,RequestMethod.GET})
public @ResponseBody String getVerifyCode(HttpServletRequest request, HttpServletResponse response){
	//生成随机字串
	String verifyCode = VerifyCodeUtils.generateVerifyCode(4);
	//存入会话session
	HttpSession session = request.getSession();
	//删除以前的
	session.removeAttribute(Constants.VERIFY_CODE);
	session.setAttribute(Constants.VERIFY_CODE, verifyCode.toUpperCase());
	//生成图片
	int w = 100, h = 40;
	VerifyCodeUtils.outputImage(w, h, response.getOutputStream(), verifyCode);
	return verifyCode;
}

然后在登录请求的时候去取,但是取到的session为null

HttpSession session = request.getSession(false);
//获取session中的验证码
String ssession_verCode=(String) session.getAttribute(Constants.VERIFY_CODE);

百思不得其解,各种百度,原来是因为跨域问题SSIONID每次请求都会变化,然而我在服务端返回时加入允许跨域的请求头,允许指定域名的跨域访问java后台,一个Filter代码如下:

import org.springframework.http.HttpHeaders;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 使用Filter的方式解决跨域问题
 */
public class CorsFilter implements Filter {
    //private static final List ALLOW_ORIGINS = Config.getListString("allowOrigins", ",");
    private static final String REQUEST_OPTIONS = "OPTIONS";
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        String orgHeader = request.getHeader(HttpHeaders.ORIGIN);
        if (orgHeader != null ) {
            // 允许的跨域的域名
            response.addHeader("Access-Control-Allow-Origin", orgHeader);
            // 允许携带 cookies 等认证信息
            response.addHeader("Access-Control-Allow-Credentials", "true");
            // 允许跨域的方法
            response.addHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PATCH, PUT, HEAD");
            // 允许跨域请求携带的请求头
            response.addHeader("Access-Control-Allow-Headers", "Content-Type, Content-Length, Authorization, Accept, X-Requested-With");
            // 返回结果可以用于缓存的最长时间,单位是秒。-1表示禁用
            response.addHeader("Access-Control-Max-Age", "3600");
            // 跨域预检请求,直接返回
            if (REQUEST_OPTIONS.equalsIgnoreCase(request.getMethod())) {
                return;
            }
        }
        filterChain.doFilter(request, response);
    }
    @Override
    public void destroy() {
    }
}

并在web.xml中添加:


  
    corsfilter
    com.yhq.filter.CorsFilter
  
  
    corsfilter
    /*
    REQUEST
  

同域安全策略CORS(Cross-Origin Resource Sharing) ,它要求请求的服务器在响应的报头(Response Header)添加 Access-Control-Allow-Origin标签,从而允许此标签所对应域访问此服务器的资源,调用此服务器的接口。
缺陷是:默认情况下,跨源请求不提供凭据(cookie、HTTP认证及客户端SSL证明等),通过将withCredentials属性设置为true,可以指定某个请求应该发送凭据。如果服务器接收带凭据的请求,会用下面的HTTP头部来响应:

Access-Control-Allow-Credentials: true

如果发送的是带凭据的请求,但服务器的相应中没有包含这个头部,那么浏览器就不会把相应交给JavaScript,请求就无法得到结果的数据(浏览器得到了,但是我们请求的方法得不到,因为被浏览器拦截了),因此在需要传Cookie等时,服务端的Access-Control-Allow-Origin必须配置具体的具体的域名,并且还需要设置其他的请求头:

 // 允许携带 cookies 等认证信息
 response.addHeader("Access-Control-Allow-Credentials", "true");
 // 允许跨域的方法
 response.addHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PATCH, PUT, HEAD");
 // 允许跨域请求携带的请求头
 response.addHeader("Access-Control-Allow-Headers", "Content-Type, Content-Length, Authorization, Accept, X-Requested-With");

对axios请求写一个工具类

import React from 'react'
import axios from 'axios'
import qs from 'qs'

axios.defaults.withCredentials = true  //一定要配置
axios.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded"
axios.defaults.timeout = 100000

/**
 * get方法,对应get请求
 * @param {String} url [请求的url地址]
 * @param {Object} params [请求时携带的参数]
 */
 function get(url, params){
    return new Promise((resolve, reject) =>{
        axios.get(url, {
            params: params
        }).then(res => {
            resolve(res.data);
        }).catch(err =>{
            reject(err.data)
        })
    });
}
/**
 * post方法,对应post请求
 * @param {String} url [请求的url地址]
 * @param {Object} params [请求时携带的参数]
 */
 function post(url, params) {
    return new Promise((resolve, reject) => {
        axios.post(url, qs.stringify(params))
            .then(res => {
                resolve(res.data);
            })
            .catch(err =>{
                reject(err.data)
            })
    });
}
export default {
    get,
    post
};

以上操作后,则能正常跨域访问并且每次访问请求保证同一个sessionid。一个跨域问题牵涉出这么多问题出来,一一解决,解决完了,发现一个问题学习了好多知识点,所以问题才是最好的的老师。

你可能感兴趣的:(前端,Java编程,axios,Java)