深入刨析tomcat 之---第10篇 how tomcat works 第13章,Response 发送错误信息 sendError

writedby 张艳涛 在浏览器中发送一个错误应用url 那么tomcat是如何发送错误的呢?

基本上是发送http 的response协议,分为两部分一部分是response设置头信息, 那么先分析一下,tomcat是如花添加响应头的

当我发送:http://localhost:8080/app4/Primitive 的时候,我的应用名字为app1 那么tomcat 会将url 的app4/Primitve进行切分,将app4 做为一个host,如果有标准StandardHost 的时候, 那么看代码

    public void invoke(Request request, Response response,
ValveContext valveContext)
throws IOException, ServletException { // Validate the request and response object types
if (!(request.getRequest() instanceof HttpServletRequest) ||
!(response.getResponse() instanceof HttpServletResponse)) {
return; // NOTE - Not much else we can do generically
} // Select the Context to be used for this Request
StandardHost host = (StandardHost) getContainer();
Context context = (Context) host.map(request, true);
if (context == null) {
((HttpServletResponse) response.getResponse()).sendError
(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
sm.getString("standardHost.noContext"));
return;
} // Bind the context CL to the current thread
Thread.currentThread().setContextClassLoader
(context.getLoader().getClassLoader()); // Update the session last access time for our session (if any)
HttpServletRequest hreq = (HttpServletRequest) request.getRequest();
String sessionId = hreq.getRequestedSessionId();
if (sessionId != null) {
Manager manager = context.getManager();
if (manager != null) {
Session session = manager.findSession(sessionId);
if ((session != null) && session.isValid())
session.access();
}
} // Ask this Context to process this request
context.invoke(request, response); }

结果是context找不到,就发送错误信息

    public void sendError(int sc, String msg)
throws IOException { if (isCommitted())
throw new IllegalStateException
(/*sm.getString("responseBase.reset.ise")*/); resp.setAppCommitted(true); ((HttpServletResponse) response).sendError(sc, msg); }

-->

    public void sendError(int status, String message) throws IOException {

        addHeader("Connection", "close");
super.sendError(status, message); }

-->

    public void sendError(int status, String message) throws IOException {

        if (isCommitted())
throw new IllegalStateException
(sm.getString("httpResponseBase.sendError.ise")); if (included)
return; // Ignore any call from an included servlet setError(); // Record the status code and message.
this.status = status; //500
this.message = message; //Cannot find message associated with key 'standardHost.noContext' // Clear any data content that has been buffered
resetBuffer(); // Cause the response to be finished (from the application perspective)
setSuspended(true); }

设置respose对象的header属性

进入 ErrorReportValve 错误页面处理类

    protected void report(Request request, Response response,
Throwable throwable)
throws IOException { // Do nothing on non-HTTP responses
if (!(response instanceof HttpResponse))
return;
HttpResponse hresponse = (HttpResponse) response;
if (!(response instanceof HttpServletResponse))
return;
HttpServletResponse hres = (HttpServletResponse) response;
int statusCode = hresponse.getStatus();
String message = RequestUtil.filter(hresponse.getMessage());
if (message == null)
message = ""; // Do nothing on a 1xx and 2xx status
if (statusCode < 300)
return;
// Do nothing on a NOT MODIFIED status
if (statusCode == HttpServletResponse.SC_NOT_MODIFIED)
return; // FIXME: Reset part of the request
/*
try {
if (hresponse.isError())
hresponse.reset(statusCode, message);
} catch (IllegalStateException e) {
;
}
*/ Throwable rootCause = null; if (throwable != null) { if (throwable instanceof ServletException)
rootCause = ((ServletException) throwable).getRootCause(); } // Do nothing if there is no report for the specified status code
String report = null;
try {
report = sm.getString("http." + statusCode, message);
} catch (Throwable t) {
;
}
if (report == null)
return; StringBuffer sb = new StringBuffer(); sb.append("<html><head><title>");
sb.append(ServerInfo.getServerInfo()).append(" - ");
sb.append(sm.getString("errorReportValve.errorReport"));
sb.append("</title>");
sb.append("<STYLE><!--");
sb.append("H1{font-family : sans-serif,Arial,Tahoma;color : white;background-color : #0086b2;} ");
sb.append("H3{font-family : sans-serif,Arial,Tahoma;color : white;background-color : #0086b2;} ");
sb.append("BODY{font-family : sans-serif,Arial,Tahoma;color : black;background-color : white;} ");
sb.append("B{color : white;background-color : #0086b2;} ");
sb.append("HR{color : #0086b2;} ");
sb.append("--></STYLE> ");
sb.append("</head><body>");
sb.append("<h1>");
sb.append(sm.getString("errorReportValve.statusHeader",
"" + statusCode, message)).append("</h1>");
sb.append("<HR size=\"1\" noshade>");
sb.append("<p><b>type</b> ");
if (throwable != null) {
sb.append(sm.getString("errorReportValve.exceptionReport"));
} else {
sb.append(sm.getString("errorReportValve.statusReport"));
}
sb.append("</p>");
sb.append("<p><b>");
sb.append(sm.getString("errorReportValve.message"));
sb.append("</b> <u>");
sb.append(message).append("</u></p>");
sb.append("<p><b>");
sb.append(sm.getString("errorReportValve.description"));
sb.append("</b> <u>");
sb.append(report);
sb.append("</u></p>"); if (throwable != null) {
StringWriter stackTrace = new StringWriter();
throwable.printStackTrace(new PrintWriter(stackTrace));
sb.append("<p><b>");
sb.append(sm.getString("errorReportValve.exception"));
sb.append("</b> <pre>");
sb.append(stackTrace.toString());
sb.append("</pre></p>");
if (rootCause != null) {
stackTrace = new StringWriter();
rootCause.printStackTrace(new PrintWriter(stackTrace));
sb.append("<p><b>");
sb.append(sm.getString("errorReportValve.rootCause"));
sb.append("</b> <pre>");
sb.append(stackTrace.toString());
sb.append("</pre></p>");
}
} sb.append("<HR size=\"1\" noshade>");
sb.append("<h3>").append(ServerInfo.getServerInfo()).append("</h3>");
sb.append("</body></html>"); try { Writer writer = response.getReporter(); if (writer != null) { Locale locale = Locale.getDefault(); try {
hres.setContentType("text/html");
hres.setLocale(locale);
} catch (Throwable t) {
if (debug >= 1)
log("status.setContentType", t);
} // If writer is null, it's an indication that the response has
// been hard committed already, which should never happen
writer.write(sb.toString());
writer.flush(); } } catch (IOException e) {
;
} catch (IllegalStateException e) {
;
} }

获取

    public PrintWriter getReporter() {

        if (isError()) {

            try {
if (this.stream == null)
this.stream = createOutputStream();
} catch (IOException e) {
return null;
}
return (new PrintWriter(this.stream)); } else { if (this.stream != null) {
return null;
} else {
try {
return (new PrintWriter(getOutputStream()));
} catch (IOException e) {
return null;
}
} } }

获取的out流 底层是   ResponseStream ,这个流我write方法底层是写到response的buffer数组中, 在connector类中,完成了调用,接着就处理发送页面

发送头的方法是sendHeaders,接着发body

上一篇:innerhtml和innertext的用法以及区别


下一篇:Mysql SQL Mode详解