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中
随机推荐
- 使用 Hexo 搭建静态博客
目录 Hexo 简介 什么是 Hexo? Hexo 安装 Hexo 建站 Hexo 配置 Hexo 自定义主题 Hexo 写作 Hexo 服务器 Hexo 生成与发布 一键部署 Hexo 站点到 gi ...
- 「10.10」神炎皇(欧拉函数)·降雷皇(线段树,DP)·幻魔皇
A. 神炎皇 很好的一道题,可能第一次在考场上遇到欧拉函数 题意:对于一个整数对 $(a,b)$,若满足 $a\times b\leq n$且$a+b$是$a\times b$的因子, 则称为神奇的数 ...
- Echarts中X轴坐标太密集,分段显示
在axisLabel中设置刻度间隔interval,再加上强制显示最大值showMaxLabel和最小值showMinLabel axisLabel: {//X轴文字 interval: day == ...
- CS 面试题目总结(问题+答案)
开源了一个新的github仓库CS 面试题目总结(问题+答案),主要总结一些CS大厂常见的面试问题,所有的问题与答案参考了网络上的许多博客和github仓库,也希望各位读者能够对这个仓库进行补充,毕竟 ...
- OpenGL 实用攻关 001 准备(开题)
开篇 这里是OpenGL学习中的随笔,会大致讲述定下的目标需求,思路和贴出认为的关键代码以及git仓库地址.会选择性的讲述途中遇到的陷阱,和注意点. 一些资源 笔者是windows 操作系统 VS 2 ...
- @EnableDiscoveryClient与Nacos自动注册
前一阵看到有篇博客说cloud从Edgware版本开始,可以不加@EnableDiscoveryClient注解,只要配置好注册中心的相关配置即可自动开启服务注册功能,比较好奇其中的原理,研究了一番特 ...
- 不藏了,这些Java反射用法总结都告诉你们
摘要:Java反射是一种非常强大的机制,它可以在同一个系统中去检测内部的类的字段.方法和构造函数.它非常多的Java框架中,都大量应用了反射技术,如Hibernate和Spring.可以说,反射机制的 ...
- POJ 1654 Area 多边形面积 G++会WA
#include<stdio.h> #include<algorithm> #include <cstring> using namespace std; type ...
- Docker:如何修改Docker0网桥的默认网段
1. 背景 Docker 服务启动后默认会创建一个 docker0 网桥(其上有一个 docker0 内部接口),它在内核层连通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络. ...
- Https:Java代码设置使用证书访问Https
设置证书进行访问或被访问操作 String keyStore = "keyStore的文件路径": String KEY_STORE_PWD = "1234"; ...