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中
随机推荐
- Windows7 如何添加excel,word到鼠标右键
1.添加word到鼠标右键新建 首先Windows键+R---->输入regedit并回车------>看到HKEY_CLASSES_ROOT展开------>找到.doc展开--- ...
- GitHub Desktop的使用,创建项目、上传文件,设置忽略文件
下载登陆之后 新建项目File--第一个New repository 然后输入项目名称,选择项目文件夹,最后点Creata repository创建项目 这只是在本地建了项目. 项目文件夹中有其他文件 ...
- 北京某大公司:SpringBean生命周期
<对线面试官>系列目前已经连载25篇啦!有深度风趣的系列! [对线面试官]Java注解 [对线面试官]Java泛型 [对线面试官] Java NIO [对线面试官]Java反射 & ...
- Python之数值运算(基础篇)
1,类型 int类型(整数型).float类型(浮点型,小数型).bool布尔值(True 或者 Fasle) str类型(字符串).list类型(列表).tuple类型(元组).set类型(集合), ...
- C# 小知识点记录
1.当计算数据有小数点时不要使用float和double类型的数据,使用这两个会计算不准确.使用decimal 2.如果使用decimal计算数据,遇到除不进的数据有很多小数点的时候,在计算结果后面接 ...
- centos 8.3关闭防火墙,设置开机启动禁用防火墙
关闭防火墙 [root@bogon ~]# systemctl stop firewalld 开机禁用防火墙 [root@bogon ~]# systemctl disable firewa ...
- Java:Java实例化(new)过程
实例化过程(new) 1.首先去JVM 的方法区中区寻找类的class对象,如果能找到,则按照定义生成对象,找不到 >>如下2.所示 2.加载类定义:类加载器(classLoader)寻找 ...
- com.rabbitmq.client.impl.Frame.readFrom(Frame.java:95)
RabbitMQ 基于Erlang 实现, 客户端可以用Python | Java | Ruby | PHP | C# | Javascript | Go等语言来实现.这里做个java语言的测试.首先 ...
- pod调度
Pod调度 在默认情况下,一个pod在哪个node节点上运行,是由scheduler组件采用相应的算法计算出来的,这个过程是不受人工控制的. 但是在实际过程中,这并不满足需求,因为很多情况下,我们想控 ...
- ESP32构建系统 (传统 GNU Make)
概述: 一个 ESP-IDF 项目可以看作是多个不同组件的集合,ESP-IDF 可以显式地指定和配置每个组件.在构建项目的时候,构建系统会前往 ESP-IDF 目录.项目目录和用户自定义目录(可选)中 ...