提交表单发起多次请求(未解之谜)

补充

示例模板CSDN下载地址:https://download.csdn.net/download/weixin_30531261/10293193
示例模板码云下载地址:https://gitee.com/LLLLLLEE/loginProblem

CSDN下载文件资源分最少要为2,额。。。

在这个示例模板中,就是简单的springmvc+jsp,省去了service和dao层。但是出现的问题是一样的(我测试过了)。我把controller类和jsp的代码放在文章最后吧。

对了,如果我在浏览器地址栏上直接访问判断登录是否成功的请求,会发起两次请求。而如果是发起其他请求(如页面跳转的请求),则只会发起一次请求。好奇怪。

其实这不是工作中的项目,本人未毕业,不解决它也是可以的,只是我好好奇,总是想着它。所以希望大神们能帮忙看看。

问题简述

问题:填写好登录界面的表单,点击登录按钮,发起多两次请求。

后端相关代码

@Controller
@RequestMapping(value = "/user")
public class UserController {

    private Logger logger = LoggerFactory.getLogger(UserController.class);

    @Autowired
    private EmployeeService employeeService;

    @ResponseBody
    @RequestMapping(value = "/login")
    public String login(@RequestParam("loginId") String loginId,
                              @RequestParam("password") String password,
                              HttpSession session){

        try{
            Thread.sleep(1000);//模拟网络延迟
        }catch (InterruptedException e){

        }
        logger.info("进到了login方法");

        if("".equals(loginId) || "".equals(password)) {
            logger.info("账号或密码为空,不访问数据库,直接返回null");
            return null;
        }
        User user = employeeService.getUserByLoginIdAndPassword(new User(loginId,password));
        if(user!=null){
            logger.info("登录成功,准备跳往主界面");
            session.setAttribute("user_session",user);
            return "/user/main";
        }else{
            logger.info("登录失败,账号密码错误");
            return null;
        }
    }
    @RequestMapping(value = "/main")
    public ModelAndView toMainWindow(ModelAndView mv){
        mv.setViewName("main_test_auth");
        return mv;//返回main_test_auth.jsp//即登录后进到的主界面
    }
//省略其他不相关的方法
}

前端代码

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <meta charset="UTF-8">
    <title>login</title>
    <link rel="stylesheet" type="text/css" href="/resources/easyUI/jquery-easyui-1.5.4.1/themes/default/easyui.css">
    <link rel="stylesheet" type="text/css" href="/resources/easyUI/jquery-easyui-1.5.4.1/themes/icon.css">
    <script type="text/javascript" src="/resources/easyUI/jquery-easyui-1.5.4.1/jquery.min.js"></script>
    <script type="text/javascript" src="/resources/easyUI/jquery-easyui-1.5.4.1/jquery.easyui.min.js"></script>
</head>

<body>

<div class="easyui-window" title="Login" style="width:320px;height:220px;" collapsible="false" minimizable="false" maximizable="false" closable="false" draggable="false" resizable="false">
    <form id="form" method="post" style="padding:10px 20px 10px 40px;">
        <p id="p">欢迎登录</p>
        <p>账号:<input class="easyui-textbox" name="loginId" data-options="prompt:'请输入账号'"></p>
        <p>密码:<input class="easyui-textbox" name="password" data-options="prompt:'请输入密码'" type="password"></p>
        <div style="padding:5px;text-align:center;">
            <button id="btn" class="easyui-linkbutton" onclick="submitForm()">登录</button>
        </div>
    </form>
</div>

</body>

<script>
    function submitForm() {
        $('#form').form('submit',{
            url:'/user/login',
            success:function (data) {
                if(data){
                    window.location.href=data;//页面跳转
                }else{
                    $('#p').text("您输入的账号或密码不正确,请重新输入");//给出提示
                }
            }
        });
    }
</script>
</html>

问题描述

理想的情况是这样的:
当账号密码填写正确,会向前台返回”/user/main”字符串,前台通过window.location.href=”/user/main”再跳转到主界面。
而当登录不通过,会返回null,则不会进行页面跳转,而是显示提示:”您输入的账号或密码不正确,请重新输入”。

而现实是,填写好表单后,点击提交,发起了两次请求。后台打印的记录为(我删除了mybatis相关的代码):

15:18:06.430 [http-nio-8080-exec-16] INFO  hrm.controller.UserController - 进到了login方法
15:18:06.434 [http-nio-8080-exec-16] INFO  hrm.controller.UserController - 登录失败,账号密码错误
15:18:06.441 [http-nio-8080-exec-14] INFO  hrm.controller.UserController - 进到了login方法
15:18:06.444 [http-nio-8080-exec-14] INFO  hrm.controller.UserController - 登录失败,账号密码错误

且由于发起了两次请求,页面变得一片空白,如图:

而账号密码正确时,也是发起了两次请求,但由于我前端使用了window.location.href=data来进行页面跳转,所以能正常显示主界面,这也是我为什么要在前端处理页面跳转,而没有直接在后端的login方法进行页面跳转的原因。(如果登录成功时我直接在后台进行页面跳转处理,也会出现页面变空白的情况。)
后台打印为:

15:24:21.711 [http-nio-8080-exec-19] INFO  hrm.controller.UserController - 进到了login方法
15:24:21.719 [http-nio-8080-exec-19] INFO  hrm.controller.UserController - 登录成功,准备跳往主界面
15:24:21.724 [http-nio-8080-exec-16] INFO  hrm.controller.UserController - 进到了login方法
15:24:21.762 [http-nio-8080-exec-16] INFO  hrm.controller.UserController - 登录成功,准备跳往主界面

由于我是在前端进行页面跳转,页面显示正常:

不知道是否跟浏览器有关

不知道是前端的问题还是后端的问题。

假如我通过浏览器地址栏直接访问,应该就不涉及到前端的问题了吧。

测试发现:

当账号密码正确时:

http://localhost:8080/user/login?loginId=jack&password=jack

只发起了一次请求:

15:33:49.659 [http-nio-8080-exec-12] INFO  hrm.controller.UserController - 进到了login方法
15:33:49.669 [http-nio-8080-exec-12] INFO  hrm.controller.UserController - 登录成功,准备跳往主界面

当账号密码不正确时(第一次),如:

http://localhost:8080/user/login?loginId=jack&password=jack1

此时,后台发起了两次请求:

15:34:47.821 [http-nio-8080-exec-19] INFO  hrm.controller.UserController - 进到了login方法
15:34:47.824 [http-nio-8080-exec-19] INFO  hrm.controller.UserController - 登录失败,账号密码错误
15:34:49.023 [http-nio-8080-exec-16] INFO  hrm.controller.UserController - 进到了login方法
15:34:49.025 [http-nio-8080-exec-16] INFO  hrm.controller.UserController - 登录失败,账号密码错误

当我再次发起上面的请求,注意是再次,也就是说我填写的url是一模一样的:

http://localhost:8080/user/login?loginId=jack&password=jack1

这时!!后台打印的是:

15:37:14.369 [http-nio-8080-exec-17] INFO  hrm.controller.UserController - 进到了login方法
15:37:14.371 [http-nio-8080-exec-17] INFO  hrm.controller.UserController - 登录失败,账号密码错误

第二次,就只发起了一次请求。

也就是说,两次输入的账号密码不正确且不完全相同,就会发起两次请求。如果这次发起的请求和上次一样,这次就会发起一次请求。不知道为什么会这样。

以上,我用的是360浏览器极速模式。

当我换成谷歌浏览器,情况又不一样了。如果是直接在地址栏上访问,不管账号密码正确与否,通过后台打印的记录查看,发现只会发起一次请求。
而当账号密码填写错误时,情况和使用360浏览器一样,页面变得空白(这应该是因为我后台返回的是null)。
当我账号密码填写正确时,页面没有正常跳转到主界面,而是这样的:

这个”/user/main”是我后台返回的数据。

后台打印的是这样的:

15:46:14.102 [http-nio-8080-exec-12] INFO  hrm.controller.UserController - 进到了login方法
15:46:14.104 [http-nio-8080-exec-13] INFO  hrm.controller.UserController - 进到了login方法
15:46:14.109 [http-nio-8080-exec-12] INFO  hrm.controller.UserController - 登录成功,准备跳往主界面
15:46:14.109 [http-nio-8080-exec-13] INFO  hrm.controller.UserController - 登录成功,准备跳往主界面

然后我换成360的兼容模式,界面显示得很奇怪:

但是通过查看控制台,发现不管账号密码填写正确与否,都只会发起一次请求。但是呢,又有一个问题,当账号密码正确时,会出现这个:

点击ok,页面也没跳转。

我的看法和疑惑

前端时间也捣鼓过,今天又捣鼓了一次,猜是浏览器问题,兼容性问题?具体是什么原因我也不知道。

当我在点击按钮时先禁用按钮点击功能,请求返回结果后才恢复按钮点击功能,可以解决一次提交发起多次请求的问题:

    function submitForm() {
        $("#btn").attr("disabled",true);//禁用按钮
        $('#form').form('submit',{
            url:'/user/login',
            success:function (data) {
                if(data){
                    window.location.href=data;//页面跳转
                }else{
                    $('#p').text("您输入的账号或密码不正确,请重新输入");//给出提示
                }
                $("#btn").attr("disabled",false);//恢复按钮
            }
        });
    }

这让我怀疑是前端的问题。我禁用了按钮的点击功能,就只会发起一次请求。我在想要不我不使用框架,直接做一个最简单的jsp表单?

可是当我通过浏览器地址栏直接发起请求时也会出现多次请求的问题,这就已经不涉及到前端界面问题了,我就懵逼了。到底是哪一个环节出了问题,难道是浏览器的问题吗?

像我用上面说的方法,虽然解决这个一次点击发起多次请求的问题,但是我还是不懂,问题出在了哪里。很奇怪,在网上搜登录模块一次提交发起多次请求,却搜不到想要的答案。难道就我才遇到这个情况吗?登录模块是很常见的模块,没道理就我一个遇到这个问题吧?

示例代码

controller层代码

package hrm;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpSession;

@Controller
@RequestMapping(value = "/user")
public class UserController {

    private Logger logger = LoggerFactory.getLogger(UserController.class);

    //进入登录界面的url
    @RequestMapping(value = "/toLogin")
    public String toLoginForm(){
        return "loginForm";
    }

    //处理登录的url
    @ResponseBody
    @RequestMapping(value = "/login")
    public String login(@RequestParam("loginId") String loginId,
                        @RequestParam("password") String password,
                        HttpSession session){

        try{
            Thread.sleep(1000);//模拟网络延迟
        }catch (InterruptedException e){

        }
        logger.info("进到了login方法");

        if("".equals(loginId) || "".equals(password)) {
            logger.info("账号或密码为空,不访问数据库,直接返回null");
            return null;
        }
        if("123".equals(loginId) || "123".equals(password)){
            logger.info("登录成功,准备跳往主界面");
            return "/user/main";
        }else{
            logger.info("登录失败,账号密码错误");
            return null;
        }
    }

    //登录验证通过后跳转的url
    @RequestMapping(value = "/main")
    public ModelAndView toMainWindow(ModelAndView mv){
        logger.info("准备进行页面跳转");
        mv.setViewName("main");
        return mv;
    }

}

而前台完整代码就是:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <meta charset="UTF-8">
    <title>login</title>
    <link rel="stylesheet" type="text/css" href="/resources/easyui.css">
    <script type="text/javascript" src="/resources/jquery.min.js"></script>
    <script type="text/javascript" src="/resources/jquery.easyui.min.js"></script>
</head>

<body>

<div class="easyui-window" title="Login" style="width:320px;height:220px;" collapsible="false" minimizable="false" maximizable="false" closable="false" draggable="false" resizable="false">
    <form id="form" method="post" style="padding:10px 20px 10px 40px;">
        <p id="p">欢迎登录</p>
        <p>账号:<input class="easyui-textbox" name="loginId" data-options="prompt:'请输入账号'"></p>
        <p>密码:<input class="easyui-textbox" name="password" data-options="prompt:'请输入密码'" type="password"></p>
        <div style="padding:5px;text-align:center;">
            <button id="btn" class="easyui-linkbutton" onclick="submitForm()">登录</button>
        </div>
    </form>
</div>

</body>

<script>
    function submitForm() {
        //$("#btn").attr("disabled",true);//禁用按钮
        $('#form').form('submit',{
            url:'/user/login',
            success:function (data) {
                if(data){
                    window.location.href=data;//页面跳转
                }else{
                    $('#p').text("您输入的账号或密码不正确,请重新输入");//给出提示
                }
                //$("#btn").attr("disabled",false);//恢复按钮
            }
        });
    }
</script>
</html>

猜你喜欢

转载自blog.csdn.net/weixin_30531261/article/details/79593202