zoukankan      html  css  js  c++  java
  • 深入刨析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

  • 相关阅读:
    如何找按钮数组在布局中的横竖坐标位置?
    java中使用rmi进行远程方法调用
    测试视频集,各种测试用的视频文件
    如何彻底禁用VS 2008的智能感知功能
    JavaScript秘密花园 Type Casting,undefined,eval,setTimeout,Auto Semicolon Insertion
    JavaScript秘密花园 scope, namespace, constructor, equality and comparisons
    造成内存位置访问无效的一个原因
    depends在VS2008消失了
    12月10日晚的月全食照片
    JavaScript秘密花园 Array, Array Constructor, for in loop, typeof, instanceOf
  • 原文地址:https://www.cnblogs.com/zytcomeon/p/15003328.html
Copyright © 2011-2022 走看看