一次ajax跨域请求SESSION不一致解决方案
场景重现:简单的登录注册模块,使用前后台分离,后台使用SpringMVC给前台提供数据接口支持,前台采用ajax请求后台数据。
一:验证码
package com.lemonzuo.service;
import java.io.IOException;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import com.lemonzuo.util.RandomVerifyImgCodeUtil;
@Controller
// 平台验证码
public class VerifyCodeService {
@Autowired
private HttpSession session;
@RequestMapping(value="VerifyCodeService.do", method=RequestMethod.GET)
public void createVerifyCode(
HttpServletResponse response,
@RequestParam(value="width", required=true, defaultValue="100") int width,
@RequestParam(value="height", required=true, defaultValue="30") int height,
@RequestParam(value="sessionName", required=true, defaultValue="verifyCode") String sessionName) {
// 设置相应类型,告诉浏览器输出的内容为图片
response.setContentType("image/jpeg");
// 设置响应头信息,告诉浏览器不要缓存此内容
response.setHeader("Pragma", "No-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expire", 0);
try {
int charSize = 4;
String verifyCode = RandomVerifyImgCodeUtil.generateVerifyCode(charSize);
// 将字符信息存入Session中
session.setAttribute(sessionName, verifyCode);
RandomVerifyImgCodeUtil.outputImage(width, height, response.getOutputStream(), verifyCode, "login");
} catch (IOException e) {
e.printStackTrace();
}
}
}
二、验证码校验
// 验证验证码的正确性
@CrossOrigin(value="http://localhost:63342")
@RequestMapping(value="/checkUserVerifyCode.do",
method=RequestMethod.POST,
produces="application/json;charset=UTF-8")
@ResponseBody
public String checkVerifyCode(
HttpSession session,
@RequestParam(value="verifyCode", required=true, defaultValue="") String verifyCode,
@RequestParam(value="sessionName", required=true, defaultValue="verifyCode") String sessionName) {
String sessionVerifyCode = (String) session.getAttribute(sessionName);
verifyCode = verifyCode.toUpperCase();
if( sessionVerifyCode != null ) {
sessionVerifyCode = sessionVerifyCode.toUpperCase();
}
if( verifyCode.equals("") ) {
msg.setMsgCode("3001");
msg.setMsgInfo("信息不完整");
msg.setMsgFlag(false);
} else if( sessionVerifyCode != null && sessionVerifyCode.equals(verifyCode)) {
msg.setMsgCode("3003");
msg.setMsgInfo("验证码正确");
msg.setMsgFlag(true);
} else {
msg.setMsgCode("3002");
msg.setMsgInfo("验证码错误");
msg.setMsgFlag(false);
}
return gson.toJson(msg);
}
三、ajax请求
/* 校验验证码 */
$('#verifyCode').on('blur', function () {
$verifyCode = $(this).val();
if( $verifyCode != null ) {
$.ajax({
type: 'POST',
url: 'http://127.0.0.1:8080/onlineLearn/checkUserVerifyCode.do',
data: {
verifyCode: $verifyCode,
sessionName: 'UserRegistVerifyCode'
},
dataType: 'json',
error: function (msg) {
showModifyMessage("服务器开小差了", "error")
},
success: function (msg) {
if( msg.msgFlag) {
showModifyMessage(msg.msgInfo, 'info');
} else {
showModifyMessage(msg.msgInfo, 'warning');
}
}
})
}
});
前台联调结果异步验证验证码的一致性验证结果为验证码不一致。
采用POSTMan验证,验证通过。
于是联想到ajax请求方式未携带jessionid,导致在浏览器端联调导致验证不通过。
解决方案如下:
前台:
/* 校验验证码 */
$('#verifyCode').on('blur', function () {
$verifyCode = $(this).val();
if( $verifyCode != null ) {
$.ajax({
type: 'POST',
url: 'http://127.0.0.1:8080/onlineLearn/checkUserVerifyCode.do',
xhrFields: {
withCredentials: true
},
data: {
verifyCode: $verifyCode,
sessionName: 'UserRegistVerifyCode'
},
dataType: 'json',
error: function (msg) {
showModifyMessage("服务器开小差了", "error")
},
success: function (msg) {
if( msg.msgFlag) {
showModifyMessage(msg.msgInfo, 'info');
} else {
showModifyMessage(msg.msgInfo, 'warning');
}
}
})
}
});
后台:
验证码:
package com.lemonzuo.service;
import java.io.IOException;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import com.lemonzuo.util.RandomVerifyImgCodeUtil;
@Controller
// 平台验证码
public class VerifyCodeService {
@Autowired
private HttpSession session;
@RequestMapping(value="VerifyCodeService.do", method=RequestMethod.GET)
public void createVerifyCode(
HttpServletResponse response,
@RequestParam(value="width", required=true, defaultValue="100") int width,
@RequestParam(value="height", required=true, defaultValue="30") int height,
@RequestParam(value="sessionName", required=true, defaultValue="verifyCode") String sessionName) {
// 设置相应类型,告诉浏览器输出的内容为图片
response.setContentType("image/jpeg");
// 解决跨域
response.setHeader("Access-Control-Allow-Credentials", "true");
// 设置响应头信息,告诉浏览器不要缓存此内容
response.setHeader("Pragma", "No-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expire", 0);
try {
int charSize = 4;
String verifyCode = RandomVerifyImgCodeUtil.generateVerifyCode(charSize);
// 将字符信息存入Session中
session.setAttribute(sessionName, verifyCode);
RandomVerifyImgCodeUtil.outputImage(width, height, response.getOutputStream(), verifyCode, "login");
} catch (IOException e) {
e.printStackTrace();
}
}
}
验证码校验:
// 验证验证码的正确性
@RequestMapping(value="/checkUserVerifyCode.do",
method=RequestMethod.POST,
produces="application/json;charset=UTF-8")
@ResponseBody
public String checkVerifyCode(
HttpSession session,
@RequestParam(value="verifyCode", required=true, defaultValue="") String verifyCode,
@RequestParam(value="sessionName", required=true, defaultValue="verifyCode") String sessionName) {
response.setHeader("Access-Control-Allow-Credentials", "true");
String sessionVerifyCode = (String) session.getAttribute(sessionName);
verifyCode = verifyCode.toUpperCase();
if( sessionVerifyCode != null ) {
sessionVerifyCode = sessionVerifyCode.toUpperCase();
}
if( verifyCode.equals("") ) {
msg.setMsgCode("3001");
msg.setMsgInfo("信息不完整");
msg.setMsgFlag(false);
} else if( sessionVerifyCode != null && sessionVerifyCode.equals(verifyCode)) {
msg.setMsgCode("3003");
msg.setMsgInfo("验证码正确");
msg.setMsgFlag(true);
} else {
msg.setMsgCode("3002");
msg.setMsgInfo("验证码错误");
msg.setMsgFlag(false);
}
return gson.toJson(msg);
}
前台:
/* 校验验证码 */
$('#verifyCode').on('blur', function () {
$verifyCode = $(this).val();
if( $verifyCode != null ) {
$.ajax({
type: 'POST',
url: 'http://127.0.0.1:8080/onlineLearn/checkUserVerifyCode.do',
xhrFields: {
withCredentials: true
},
data: {
verifyCode: $verifyCode,
sessionName: 'UserRegistVerifyCode'
},
dataType: 'json',
error: function (msg) {
showModifyMessage("服务器开小差了", "error")
},
success: function (msg) {
if( msg.msgFlag) {
showModifyMessage(msg.msgInfo, 'info');
} else {
showModifyMessage(msg.msgInfo, 'warning');
}
}
})
}
});
浏览器端联调结果验证码一致性校验验证通过。
关键设置点
/* Access-Control-Allow-Origin 禁用 * */
response.setHeader("Access-Control-Allow-Origin", "具体域");
response.setHeader("Access-Control-Allow-Credentials", "true");
前台ajax请求中
/* ajax请求中加入 */
xhrFields: {
withCredentials: true
}