异步线程处理request,导致参数获取为null

原文链接:千万不要把 Request 传递到异步线程里面!有坑!

一、post接口

接口参数:

 后端代码:

@PostMapping("/postTest")
public String postTest(HttpServletRequest request, HttpServletResponse response) {
    // AsyncContext asyncContext = request.startAsync(request, response);
    String age1 = request.getParameter("age");
    String name1 = request.getParameter("name");
    System.out.println("age1=" + age1 + ",name1=" + name1);
    new Thread(new Runnable() {
        @Override
        public void run() {
            String age2 = request.getParameter("age");
            String name2 = request.getParameter("name");
            System.out.println("age2=" + age2 + ",name2=" + name2);
            //模拟业务请求
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            age2 = request.getParameter("age");
            name2 = request.getParameter("name");
            System.out.println("age2=" + age2 + ",name2=" + name2);
            // asyncContext.complete();
        }
    }).start();
    return "post success";
}

执行结果:

注:多次请求,打印结果不变

 原因:

因为 request 在 Tomcat 中是循环使用的,第一次和第二次获取参数时,request 还没有被回收,sleep 设置为10秒,第三次获取参数前,request 已经被回收。

二、get接口

接口参数:

http://127.0.0.1:18086/finger-print/asyncRequestController/getTest?age=18

后端代码:

@GetMapping("/getTest")
public String getTest(HttpServletRequest request, HttpServletResponse response) {
    // AsyncContext asyncContext = request.startAsync(request, response);
    String age = request.getParameter("age");
    System.out.println("age=" + age);
    new Thread(() -> {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        String age1 = request.getParameter("age");
        System.out.println("age1=" + age1);
        // asyncContext.complete();
    }).start();
    return "success";
}

执行结果:

 注:两次请求结果不一致,第二次请求两次获取参数都为空

原因:

第一次请求,获取参数为空原因和 post 请求一样,第二次请求获取参数都为空的原因,与获取参数的原理有关,详细建议打开原文链接学习,这里只简单说明。

请求第一次获取参数时,会把所有入参解析到一个 map 中,并给出一个标识(didQueryParameters = true),表明参数已解析,后面获取参数都到 map 中获取,所以第一次打印 age 正常。

而第一次打印 age1 时,是在 sleep 2秒后,这时request已被回收利用,且 didQueryParameters 也被赋值为 false,map 也被清空,所以获取为null,并且第一次打印 age1,会导致  didQueryParameters 又被赋值为 true,但是异步线程的调用已经超出了 request 的生命周期,不会再被回收,所以 didQueryParameters 不会再改为 false。

因此第二次打印 age 时,不会重新进行解析参数到 map 中的操作,打印结果依然为 null。

第二次打印 age1,步骤同第一次打印 age1。

三、解决方案

这样在请求结束后,request不会被回收。

 

posted @ 2024-02-23 15:50  想看云飞却没风~  阅读(67)  评论(0编辑  收藏  举报