Ajax发送Post请求,后端控制器使用重定向页面没有自动跳转

问题描述

前端的form表单提交,Ajax发送了一个post请求,后端控制器方法处理后,进行页面跳转时,发现无法进行自动跳转。
前端代码:

<form action="" method="post" id="form1">
<!-- 此处省略form表单中的内容-->
    <button id="regbtn" type="button" name="registerSubmit" onclick="register()"
            class="btn btn-primary">注册
    </button>
</form>
function register() {
    $.ajax({
        type: "POST",
        dataType: "",
        url: "/account/saveUser",
        data: $('#form1').serialize(),
    });
}

后端代码:

@GetMapping("/account/enable")
public String enable() {
    return "login/enable";
}

@PostMapping("/account/saveUser")
public String verify() {
	//doSomething...
	return "redirect:/account/enable";
}

需要说明的是如果直接访问/account/enable,可以跳转指定的页面,但如果通过ajax发起的请求,后端代码重定向的结果,浏览器并没有自动跳转到激活页面,还是在原来的注册页面,我们通过开发者工具查看请求的情况。
在这里插入图片描述
可以看到请求方法重定向和页面跳转的请求都是成功的,但是为什么浏览器的页面没有自动跳转呢?

原因解析

Ajax实际上是通过XMLHttpRequest来向服务器发送异步请求的,从服务器获取数据,然后使用JS来更新页面,这也就是常说的局部刷新实现方式,所以Ajax请求之后,服务器返回的都是纯文本流,客户端的浏览器在获取Ajax异步结果时,不是直接显示在页面上,而是要通过JS来进行处理,JS处理完以后才能显示在页面上。此处对应的JS处理就是在Ajax回调函数中执行window.location.href=path
在这里插入图片描述
在请求头信息中有这么一条:X-Requested-With: XMLHttpRequest,这就表明这是一个AJAX请求,我们可以通过这一信息来辨别请求是来自一般的HTTP请求还是Ajax请求。

解决方法

因为Ajax本身就是局部刷新,不会重新加载页面的。所以需要前后端一起配合解决。
后端:在控制器的方法再加个Ajax请求判断,判断是否是ajax请求不是就进行重定向是就直接转发,但是要添加自定义头部信息。
前端:在Ajax回调函数中进行判断,即判断请求头中是否包含了我们设置的信息,如果是,则执行跳转。

@GetMapping("/enable")
public String enable() {
    return "login/enable";
}

@PostMapping("/saveUser")
public void verify(HttpServletRequest request, HttpServletResponse response) 
		throws IOException{
		
	//doSomething...
	
	String type = request.getHeader("X-Requested-With");
	if ("XMLHttpRequest".equals(type)) {
    	//处理AJAX请求,设置响应头信息
   		response.setHeader("REDIRECT", "REDIRECT");
    	//需要跳转页面的URL
    	response.setHeader("CONTEXTPATH", "/account/enable");
	} else {
    	//其他的http请求,直接重定向就可以了
    	response.sendRedirect("/account/enable");
	}
}
function register() {
    $.ajax({
        type: "POST",
        dataType: "",
        url: "/account/saveUser",
        data: $('#form1').serialize(),
        complete: function (XMLHttpRequest) {
            // 通过xhr取得响应头
            const REDIRECT = XMLHttpRequest.getResponseHeader("REDIRECT");
            //如果响应头中包含 REDIRECT 则说明是我们需要进行重定向的
            if (REDIRECT == "REDIRECT") {
                window.location.href = XMLHttpRequest.getResponseHeader("CONTEXTPATH");
            }
        }
    });
}

携带参数进行重定向

RedirectAttributes的使用

RedirectAttributes是Spring mvc 3.1版本之后出来的一个功能,专门用于重定向之后还能带参数跳转的。
它有两种带参的方式:
第一种
attr.addAttribute("param", value);
这种方式就相当于重定向之后,在url后面拼接参数,这样在重定向之后的页面或者控制器再去获取url后面的参数就可以了,但这个方式因为是在url后面添加参数的方式,所以暴露了参数,有风险。
例:

attr.addAttribute("name", "123"); 
attr.addAttribute("success", "success");
return "redirect:/index";

相当于:return "redirect:/index?name=123&success=success"
第二种
attr.addFlashAttribute("param", value);
这种方式也能达到重新向带参,而且能隐藏参数,其原理就是放到session中,session在跳到页面后马上移除对象。所以你刷新一下后这个值就会丢掉。

attr.addFlashAttribute("status","999");
attr.addFlashAttribute("message","登录失败");
return "redirect:/toLogin";

使用RedirectAttributes携带参数进行重定向例子

@RequestMapping("/zh")
   public String reZh(RedirectAttributes attr){
       attr.addAttribute("time","ssssss");
       attr.addFlashAttribute("hi","hello");
       return "redirect:/date?time={time}";
 }
 
 
 @GetMapping("/date")
  public String toDate(@RequestParam(value = "time",required = false)String s,HttpServletRequest request){
       Object hi = RequestContextUtils.getInputFlashMap(request).get("hi");
       System.out.println(hi);
       return s;
   }

小疑惑

在上述解决重定向页面没有自动跳转的例子中,如果还需要传递参数,因为是在Ajax回调函数中进行的重定向,那么RedirectAttributes携带的参数也就失效了,那么就只能在访问路径后面拼接参数了,但是不是很优雅也不安全。有没有在Ajax回调函数里不是拼接参数的方法进行重定向的呢?不想使用localStorage或sessionStorage(因为不优雅不安全)。

如果是上面这种form表单检查提交的话,不使用Ajax请求,会更简单些。

<form action="/account/saveUser" method="post" id="form1>
    <button id="regbtn" type="submit" onclick="return doRegister()">注册</button>
</form>

只要在doRegister()方法进行检查不合格则返回false, 则表单不会进行提交;只有返回true, 表单才会提交。

猜你喜欢

转载自blog.csdn.net/CPOHUI/article/details/106067201
今日推荐