Tom_No_02 Servlet向流中打印内容,之后在调用finsihResponse,调用上是先发送了body,后发送Header的解释
上次在培训班学上网课的时候就发现了这个问题,一直没有解决,昨天又碰到了,2-3小时也未能发现点端倪,今早又仔细缕了下,让我看了他的秘密
1.Servlet向流中打印内容,之后在调用finsihResponse,调用上是先发送了body,后发送Header的问题描述
public class ServletProcessor {
public void process(HttpRequest request,HttpResponse response){
...
try {
servlet = (Servlet) myClass.newInstance();
HttpRequestFacade requestFacade = new HttpRequestFacade(request);
HttpResponseFacade responseFacade = new HttpResponseFacade(response);
servlet.service(requestFacade, responseFacade);//先调用servlet代码
((HttpResponse) response).finishResponse();//后执行完成response
}
catch (Exception e) {
System.out.println(e.toString());
}
catch (Throwable e) {
System.out.println(e.toString());
}
}
}
servlet.service(requestFacade, responseFacade);//先调用servlet代码
public class PrimitiveServlet implements Servlet { public void init(ServletConfig config) throws ServletException {
System.out.println("init");
}
public void service(ServletRequest request, ServletResponse response)
throws ServletException, IOException {
System.out.println("from service");
PrintWriter out = response.getWriter();//这里是关键稍后分析
out.println("Hello. Roses are red.");//打印
out.print("Violets are blue.");
}
public void destroy() {
System.out.println("destroy");
}
public String getServletInfo() {
return null;
}
public ServletConfig getServletConfig() {
return null;
} }
((HttpResponse) response).finishResponse();//后执行完成response
public void finishResponse()throws IOException{
sendHeaders();
// Flush and close the appropriate output mechanism
if(writer !=null){
writer.flush();
System.out.println("finishResponse writer.flush");
writer.close();
}
} protected void sendHeaders() throws IOException{
if(isCommitted())
return;
OutputStreamWriter osr=null;
try{
osr=new OutputStreamWriter(getStream(),getCharacterEncoding());
}catch (UnsupportedEncodingException e) {
osr = new OutputStreamWriter(getStream());
}
final PrintWriter outputWriter = new PrintWriter(osr);
outputWriter.print(this.getProtocol());
outputWriter.print(" ");
outputWriter.print(status);
if(message!=null){
outputWriter.print(" ");
outputWriter.print(message); //OK 状态描述
}
outputWriter.print("\r\n");
if (getContentType()!=null){
outputWriter.print("Content-Type: " + getContentType() + "\r\n");
}
if(getContentLength()>=0){
outputWriter.print("Content-Length: " + getContentLength() + "\r\n");
}
synchronized (headers){
Iterator items=headers.keySet().iterator();
while(items.hasNext()){
String name=(String)items.next();
ArrayList list =(ArrayList) headers.get(name);
Iterator iterator = list.iterator();
while (iterator.hasNext()){
String value = (String)iterator.next();
outputWriter.print(name);
outputWriter.print(": ");
outputWriter.print(value);
outputWriter.print("\r\n");
}
}
}
synchronized (cookies){
Iterator items=cookies.iterator();
while(items.hasNext()){
Cookie cookie=(Cookie)items.next();
outputWriter.print(CookieTools.getCookieHeaderName(cookie));
outputWriter.print(": ");
outputWriter.print(CookieTools.getCookieHeaderValue(cookie));
outputWriter.print("\r\n");
}
}
// Send a terminating blank line to mark the end of the headers
outputWriter.print("\r\n");
outputWriter.flush();
System.out.println("给response的header发送完成"); committed = true;
}
问题描述完毕
2.突破口,在sendHeader中的outputWriter与servlet中的 PrintWriter out = response.getWriter();不是一个东西
先说sentHader中的
try{
osr=new OutputStreamWriter(getStream(),getCharacterEncoding());
}catch (UnsupportedEncodingException e) {
osr = new OutputStreamWriter(getStream());
}
final PrintWriter outputWriter = new PrintWriter(osr);
outputWriter.print(this.getProtocol());
outputWriter.print(" ");
outputWriter.print(status);
其中
public OutputStream getStream(){
return this.output;
}
构造方法
public HttpResponse(OutputStream output)
{
this.output=output;
}
他被调用位置见图片
小结:sendheader中的PrintWriter就是使用了outputSteam做为底层的输出流
3.servlet中的 PrintWriter out = response.getWriter()的包裹关系
public PrintWriter getWriter() throws IOException{
ResponseStream newStream = new ResponseStream(this);
newStream.setCommit(false);
OutputStreamWriter osr=
new OutputStreamWriter(newStream,getCharacterEncoding());
writer=new ResponseWriter(osr);
return writer;
}
见解释图
说明:
1.servlet中getWrter得到是ResponseWriter,调用responseWriter的frint("")方法,通过流的调用,最后底层流是ResponseStream,调用其方法为writer(...)
writer方法是将"Rode Are Red" 字符串写入到HttpResponse的成员变量buff中
2.在调用close的时候,最后调用ResponseStream的close方法,接着在flushbuffer中才最终叫内容"Rode Are Red",发送给浏览器
几张debugger图
atzhang
Tom_No_02 Servlet向流中打印内容,之后在调用finsihResponse,调用上是先发送了body,后发送Header的解释的更多相关文章
- 使用定时器实现在console中打印内容
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 用servlet在网页中打印字符串(初接触)、servlet调用过程
一.servlet是什么: 二.在官方文档中点servlet 这就是servlet的方法,这里说一下什么叫生命周期的方法(life-cycle methods):就是这个对象一旦创生之后一定会执行的方 ...
- 从servlet向jsp中传数据用Java接收js调用
servlet: response.sendRedirect("showMessage.jsp?ValueA=1"); jsp: var a=<%=request.getPa ...
- H264码流中SPS PPS详解<转>
转载地址:https://zhuanlan.zhihu.com/p/27896239 1 SPS和PPS从何处而来? 2 SPS和PPS中的每个参数起什么作用? 3 如何解析SDP中包含的H.264的 ...
- 描述了say_hello函数的具体内容,调用zend_printf系统函数在php中打印字符串
下载一个php的源代码包,这里使用的是php 4.0.5版,解压后会看到php的根目录下会有README.EXT_SKEL这样一个文件,打开详细阅读了一下,发现了一个非常好用的工具,这个工具可以帮你构 ...
- js打印Iframe中的内容,并且不需要预览。
js打印Iframe中的内容,并且不需要预览 js代码如下: <script type="text/javascript" language="Javascript ...
- window.print打印指定html元素中的内容
通常有些时候我们项目过程中使用到打印功能,而wndow.print便是系统里提供的一个函数. 但是直接使用的话,它打印的将是整个页面的所有元素,而有些时候我们又只需要打印部分内容. <body& ...
- 1.关于QT中的Graphics绘图,定时器,动画,将窗口中的内容打印到图片上,打印机,打印预览
1 新建项目 A 修改pro中的内容如下: HEADERS += \ MyWidget.h SOURCES += \ MyWidget.cpp QT += gui widgets prints ...
- 过滤器将获取到的内容注入到servlet的request中
过滤器将获取到的内容注入到servlet的request中
随机推荐
- 痞子衡嵌入式:超级下载算法(RT-UFL)开发笔记番外(1) - JLinkScript妙用
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是超级下载算法开发笔记番外篇之JLinkScript妙用. JLinkScript 文件是配套 J-Link 调试器使用的脚本,这个脚本适 ...
- Webflux请求处理流程
spring mvc处理流程 在了解SpringMvc的请求流程源码之后,理解WebFlux就容易的多,毕竟WebFlux处理流程是模仿Servlet另起炉灶的. 下面是spring mvc的请求处理 ...
- JavaScript中基本数据类型和引用数据类型的区别(栈——堆)
JavaScript中基本数据类型和引用数据类型的区别 1.基本数据类型和引用数据类型 ECMAScript包括两个不同类型的值:基本数据类型和引用数据类型. 基本数据类型指的是简单的数据段,引用数据 ...
- 题解 P3233 [HNOI2014]世界树
题目传送门 解题思路 正解当然是虚树了. 首先对于原树以及虚树各开一个结构体存边,这个不用多说. 然后我们先 DFS 一遍,求出各个节点的时间戳,子树大小,深度以及父亲节点,并初始化倍增 LCA . ...
- Oracle不知道用户密码情况下,如何在不更改密码的前提下解锁用户或者延期密码有效期
1.问题描述: 生产环境,zabbix告警业务用户密码即将过期,但是如何不知道业务用户密码的情况下来解决该问题? 2.实验一: 1)创建新的用户test,并授予test resource角色和conn ...
- 29、Tomcat只允许指定域名访问,禁用IP地址访问,防止恶意解析
1.1.测试环境说明: Linux版本:7.6 IP地址:10.11.220.123/24 Tomcat版本:tomcat-8.5.37(端口号为8080) Jdk版本:1.8.0_202 1.2.配 ...
- JVM到底是什么呢
在我们运行和调试Java程序的时候,经常会提到一个JVM的概念.那JVM到底是什么呢? JVM是Java程序的运行环境,它同时也是一个操作系统的一个应用程序.一个进程,因此他也有他自己的运行生命周期, ...
- Vue 消除Token过期时刷新页面的重复提示
1.问题现象 页面长时间未操作,再刷新页面时,第一次弹出"token失效,请重新登录!"提示,然后跳转到登录页面,接下来又弹出了n个"Token已过期"的后 ...
- SpringMVC(6)数据验证
在系列SpringMVC(4)数据绑定-1.SpringMVC(5)数据绑定-2中我们展示了如何绑定数据,绑定完数据之后如何确保我们得到的数据的正确性?这就是我们本篇要说的内容 -> 数据验证. ...
- log4j和log4j2的配置部分
log4j和log4j2的功能及形式对比 http://blog.csdn.net/fangaohua200/article/details/53561718 log4j2的proptise配置 ht ...