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