当前位置: 首页 > 编程笔记 >

tomcat何时写回响应数据报的详析

苗阳
2023-03-14
本文向大家介绍tomcat何时写回响应数据报的详析,包括了tomcat何时写回响应数据报的详析的使用技巧和注意事项,需要的朋友参考一下

疑问的产生

这个疑问是我在写文件下载的时候产生的,我是用HttpServletResponse获取到Outputstream,然后利用OutputStream直接写数据的。当时我就想这个OutputStream是不是就是对应的Socket连接的OutputStream。即是不是的程序在用stream写的时候,数据也同时在发?

Response的OutputStream把数据写到哪去?

于是我看了下HttpServletResponse的getOutputStream方法,看看它注释是怎么说的。

/**
  * Returns a {@link ServletOutputStream} suitable for writing binary 
  * data in the response. The servlet container does not encode the
  * binary data. 
  *
  * <p> Calling flush() on the ServletOutputStream commits the response.
  *
  * Either this method or {@link #getWriter} may 
  * be called to write the body, not both, except when {@link #reset}
  * has been called.
  *
  * @return a {@link ServletOutputStream} for writing binary data 
  *
  * @exception IllegalStateException if the <code>getWriter</code> method
  * has been called on this response
  *
  * @exception IOException if an input or output exception occurred
  *
  * @see #getWriter
  * @see #reset
  */
 public ServletOutputStream getOutputStream() throws IOException;

以上,注释有说明是OutputStream是用来写响应body内容的,也有提到flush()方法,说明肯定是有缓冲的,所以应该不是直接操作socket写数据。我猜测应该是有一个字节数组用来暂时存储,然后统一flush。但是还是不太确定,于是简单翻阅了下tomcat源码。

找到ServletOutputStream的实现类CoyoteOuputStream。它实现了OutputStream的抽象方法write,把数据写入到OutputBuffer类型的字段中存着。而这个OutputBuffer对象来自于coyote/Response。其实这个OutputBuffer也只是一个接口,具体实现一直向下翻是StreamOutputBuffer。数据大小没有限制,是用链表存储的,每个链表节点存储8196字节。

什么时候把响应数据报返回给客户端?

其实就是查看,它是何时调用OutputBuffer的flush方法的。我逐层查看,最终定位到了connector/Response的finishResponse()方法。这个方法,会先发送响应行和响应头。然后再发送响应body。Tomcat的源码我看的不多,这里找到一张不错的时序图,描述的是一个HTTP请求的处理过程。如下,我们把重点放在servlet的service方法调用,和Response的fininshResponse方法调用上。可以得到,在service方法返回后,执行的就是finishResponse操作。也就是说,当servlet程序处理完这个请求后,tomcat就会把响应结果发回客户端

注意:servlet的程序不参与底层数据的收发,或者说不控制

servlet的service方法调用在图中哪里?

包含在ApplicationFilterChain的internalDoFilter方法中。

servlet程序处理请求指的是什么?

根本上servlet程序做的工作就是,根据Request的信息,填充Response信息而已。

servlet程序与Spring MVC是什么关系?

Spring MVC底层还是Serlvet,它是把所有请求都用一个servlet处理,这个servlet叫做DispatcherServlet,而它又把请求分发给对应的@RequestMapping标注的方法进行处理。整体上来说就是完成一个service方法的调用。

那MVC的返回页面,返回REST数据是怎么回事?

返回页面就是把页面数据写入到响应Body中;@ResponseBody注解,实际上就是把@RequestMapping标注的方法的返回值转为JSON字符串写入到响应Body中。这里的响应Body指的就是前文中的OutputBuffer.

Tomcat与Servlet程序的职责

《How Tomcat works》中讲到,Servlet容器(Tomcat就是一种Servlet容器)的任务有概括地讲有三个

1.创建一个Request对象,并填充相关信息(parameters、headers、cookie、uri等)

2.创建一个Response对象

3.调用与此请求关联的Servlet的service方法,把Request和Response传给它。

这里我用自己的话讲一下:当浏览器向服务端发来一个请求时,服务端会将请求数据报的内容解析出来,创建一个填充有请求信息的Request对象,同时创建一个"空的"Response对象,然后把这两个对象传给servlet的service方法,让它来完成Response对象的填充,最后把Response数据发送给客户端。

为什么要传Request对象?

你不传Request对象,Servlet程序就不知道该填充什么。换句话说,它不知道你到底想要什么资源。

Tomcat是如何找到请求关联的Servlet的?

我们知道,Tomcat在开发的时候不可能知道你会往它里面部署什么项目,servlet程序叫什么。所以它不可能硬编码来调用service方法,它所使用的就是反射机制。

想想在使用spring boot框架开发之前,我们是怎么部署项目的?就是把项目打包,然后放到Tomcat的webapp目录下。跑起来后,项目对应的URL就是localhost:8080/projectName/xxx这样是吧。而且,在项目中,不管是注解式的,还是web.xml式,都会配置Servlet程序的映射。把URL映射到某个Servlet类文件。

当请求来临时,先根据projectName找到对应项目,再根据后续的URL映射到对应的Servlet类名。之后Tomcat就会利用反射机制加载Servlet类文件,获取实例,然后再调用service方法。

coyote/Response、connector/Response、connector/ResponseFacade之间的关系?

coyote/Response主要就是跟底层的数据传递挂钩的,而connector/Response是coyote/Response的上层包装,它实现了HttpServletResponse接口。但是如果将它直接传给service方法,则害怕用户直接将HttpServletResponse强转为connector/Response,直接调用底层的一些方法。所以引入了一个使用"Facade模式",将connector/Response除了HttpServletResponse接口定义的public方法都屏蔽掉。也就是说,传递给service的实际上是connector/ResponseFacade对象,就算强转为实际类型,也只能看到HttpServletResponse接口定义的方法。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对小牛知识库的支持。

 类似资料:
  • 问题内容: 我想返回axios的响应,但始终返回的响应是不确定的: 控制台始终记录为未定义。他们以任何方式返回此响应。 问题答案: console.log不会等到该功能完全完成后再进行记录。这意味着您将必须进行异步处理,主要有两种方法: 回调-这是当您将函数作为参数传递到现有函数中时,将在axios调用完成后执行。这是如何与您的代码一起使用的: Promise-实现此目的的最简单方法是将其放在函数

  • 问题内容: 在我的科目表中,我按学期和月份列出了所有学生的课程,每个月的分数 这就是我尝试过的 我从查询中获得的当前输出是每个查询的多个响应,因为我可以将其更改为,但不会获取其他数据 我的问题是我如何将它们合并为一个响应,并在预期的输出中返回以下数据(我在每个字段中添加了一些说明以对其进行解释) 预期产量 问题答案: 问题是,您想获取主题,而不是学生。因此,我反转了FROM和LEFT JOIN。因

  • 我正在从前端向后端中的路由发出请求,该路由正在验证与用户关联的令牌,如果令牌已过期,则会将错误响应发送回前端。我正在发送一些,但是在执行捕获块中的错误消息,未显示沿错误响应发送的json。 像这样发送错误响应 但是我在前端的 catch 块中得到的响应没有收到错误时发送的 json 的迹象。 岗位http://localhost:3001/check-验证401(未经授权)错误:请求失败,在XML

  • 本文向大家介绍解决Django响应JsonResponse返回json格式数据报错问题,包括了解决Django响应JsonResponse返回json格式数据报错问题的使用技巧和注意事项,需要的朋友参考一下 代码 return JsonResponse({"name": "tom"}) 报错: TYPEERROR: In order to allow non-dict objects to be

  • Vue中最为开发者们所津津乐道的特性就是其数据响应特性,Vue中的数据响应特性主要包含:响应数据赋值、watch观察数据和computed计算属性,该能力让我们能够以非常直观简洁的方式建立起数据与数据之间/数据与视图之间的绑定依赖关系,大幅提升复杂webapp的开发体验和开发效率。 受此启发,Mpx通过增强的方式在小程序开发中提供了完整的数据响应特性,在2.5.x版本前,Mpx通过mobx实现内部

  • 本文向大家介绍详解实现vue的数据响应式原理,包括了详解实现vue的数据响应式原理的使用技巧和注意事项,需要的朋友参考一下 这篇文章主要是给不了解或者没接触过 vue 响应式源码的小伙伴们看的,其主要目的在于能对 vue 的响应式原理有个基本的认识和了解,如果在面试中被问到此类问题,能够知道面试官想让你回答的是什么?「PS:文中如有不对的地方,欢迎小伙伴们指正」 响应式的理解 响应式顾名思义就是数