1. 程式人生 > 實用技巧 >Tomcat簡單實現-- 5.2 HttpServer

Tomcat簡單實現-- 5.2 HttpServer

HttpServer

  • 現在我們的Connector類比較繁瑣不簡潔,因為它既要接收請求,又要處理請求,現在專門用一個類HttpServer來接管請求處理這一部分功能。

HttpServer類

  • 接管處理部分,所以要有handle200(), handle404(),handle500()函式等等。

  • package jerrymice.catalina;
    
    import cn.hutool.core.io.FileUtil;
    import cn.hutool.core.util.ArrayUtil;
    import cn.hutool.core.util.StrUtil;
    import cn.hutool.log.LogFactory;
    import jerrymice.http.Request;
    import jerrymice.http.Response;
    import jerrymice.util.Constant;
    import jerrymice.util.WebXmlUtil;
    
    import java.io.File;
    import java.io.IOException;
    import java.io.OutputStream;
    import java.net.Socket;
    
    /**
     * @author :xsliu
     * @date :Created in 2020/8/18 17:18
     * @description:接管Connector類中對請求的處理部分
     * @modified By:
     */
    public class HttpServer {
        public void execute(Socket socket, Request request, Response response){
            // 處理請求和響應
            try{
                String uri = request.getUri();
                if (uri == null) {
                    // 說明此時沒有請求過來
                    return;
                }
                Context context = request.getContext();
                if ("/500.html".equals(uri)) {
                    throw new Exception("this is a deliberately created ");
                }
                if ("/".equals(uri)){
                    //如果訪問根目錄
                    uri = WebXmlUtil.getWelcomeFile(request.getContext());
                }
                String fileName = StrUtil.removePrefix(uri, "/");
                // 獲取檔名
                File file = FileUtil.file(context.getDocBase(), fileName);
                // 通過context獲取資料夾,然後通過資料夾和檔名來獲取檔案
                if (file.exists()){
                    // 如果訪問的檔案存在,就根據這個獲取字尾名
                    String extName = FileUtil.extName(file);
                    // 根據字尾名獲取瀏覽器解析該檔案時使用的mimeType
                    String mimeType = WebXmlUtil.getMimeType(extName);
                    response.setContentType(mimeType);
                }
                else{
                    //檔案不存在,返回404錯誤
                    handle404(socket, uri);
                   return;
                }
                handle200(socket, response);
            }catch (Exception e) {
                LogFactory.get().info(e.toString());
                handle500(socket, e);
            }finally {
                try{
                    if (!socket.isClosed()){
                        socket.close();
                    }
                }catch (IOException e){
                    LogFactory.get().info(e.toString());
                }
            }
        }
    
        /**
         * 處理檔案不存在異常
         */
        private void handle404(Socket socket, String uri) throws IOException {
            OutputStream outputStream = socket.getOutputStream();
            String responseText = StrUtil.format(Constant.textFormat404, uri, uri);
            responseText = Constant.responseHead404 + responseText;
            byte[] responseBytes = responseText.getBytes("utf-8");
            outputStream.write(responseBytes);
        }
    
        /**
         * 處理正常響應
         */
    
        private void handle200(Socket socket, Response response) throws IOException{
            String contentType = response.getContentType();
            String headText = Constant.responseHead200;
            byte[] head = headText.getBytes();
            byte[] body = response.getBody();
            byte[] responseBytes = new byte[head.length + body.length];
            ArrayUtil.copy(head, 0, responseBytes, 0, head.length);
            ArrayUtil.copy(body, 0, responseBytes, head.length, body.length);
    
            OutputStream outputStream = socket.getOutputStream();
            outputStream.write(responseBytes);
        }
    
        /**
         * 處理訪問時出現的問題
         * @param socket: 訪問通訊過程中所使用的socket
         * @param e: 異常
         */
        private void handle500(Socket socket, Exception e){
            try{
                OutputStream outputStream = socket.getOutputStream();
                StackTraceElement[]  stackTraceElements = e.getStackTrace();
                StringBuffer stringBuffer = new StringBuffer();
                stringBuffer.append(e.toString());
                stringBuffer.append("\r\n");
                for (StackTraceElement element : stackTraceElements) {
                    stringBuffer.append("\t");
                    stringBuffer.append(element.toString());
                    stringBuffer.append("\r\n");
                }
                String msg = e.getMessage();
                if (null != msg && msg.length() > 20){
                    msg = msg.substring(0, 19);
                }
    
                String text = StrUtil.format(Constant.textFormat500, msg, e.toString(), stringBuffer.toString());
                text = Constant.responseHead500 + text;
                byte[] responseBytes = text.getBytes("utf-8");
                outputStream.write(responseBytes);
            }catch(IOException e1){
                LogFactory.get().info(e1.toString());
            }
        }
    }
    
    

Connector類

  • Connector類中的處理部分可以去掉了,只負責接收請求。

  • package jerrymice.catalina;
    
    import cn.hutool.core.io.FileUtil;
    import cn.hutool.core.util.ArrayUtil;
    import cn.hutool.core.util.StrUtil;
    import cn.hutool.log.LogFactory;
    import com.sun.org.apache.bcel.internal.ExceptionConst;
    import jerrymice.http.Request;
    import jerrymice.http.Response;
    import jerrymice.util.Constant;
    import jerrymice.util.ThreadUtil;
    import jerrymice.util.WebXmlUtil;
    
    import java.io.File;
    import java.io.IOException;
    import java.io.OutputStream;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.nio.charset.StandardCharsets;
    
    /**
     * @author xsl20
     */
    public class Connector implements Runnable{
    
        int port;
        private Service service;
    
        public Service getService(){
            return service;
        }
        public void setPort(int port){
            this.port = port;
        }
        public Connector(Service service){
            this.service = service;
        }
    
        public void init(){
            LogFactory.get().info("Initializing Protocol [http-bio-{}], port");
        }
    
        public void start(){
            LogFactory.get().info("Starting ProtocolHandler [http-bio-{}],port");
            new Thread(this).start();
        }
    
        @Override
        public void run() {
            try{
                ServerSocket serverSocket = new ServerSocket(port);
                while(true) {
                    Socket socket = serverSocket.accept();
                    Runnable r = () -> {
                        try {
                            Request request = new Request(socket, service);
                            Response response = new Response();
                            HttpServer httpServer = new HttpServer();
                            httpServer.execute(socket, request, response);
                        }catch (Exception e){
                            LogFactory.get().info(e.toString());
                        }finally {
                            // 將socket的關閉提取到最後
                            try{
                                socket.close();
                            }catch(IOException e){
                                LogFactory.get().info(e);
                            }
                        }
                    };
                    ThreadUtil.run(r);
                }
            }catch (IOException e) {
                LogFactory.get().info(e);
            }
        }
    }
    

執行測試