1. 程式人生 > >自己動手寫Web容器之TomJetty之四:靜態頁面起步

自己動手寫Web容器之TomJetty之四:靜態頁面起步

        上一節我們實現了將HTTP請求頭的內容解析後列印到控制檯上,讓HTTP請求頭的各個組成部分完全暴露在在我們面前。這個功能在IE瀏覽器的一款叫作HttpWatch的外掛中有類似的體現,相信很多讀者都用過它,利用HttpWatch檢視網頁請求和響應的日誌資訊功能來除錯程式。前面講到我們把HTTP請求頭封裝在RequestHeader類中,這個類有一個url屬性,本節我們將利用它來定位伺服器端的靜態頁面。

1服務端靜態頁面

        作為一個Web伺服器,響應客戶端傳送的請求是首要任務,怎樣設計它才能快速地響應請求呢?前面我們提到,現在的網站架構普遍採用CMS模式,就是採用靜態網頁技術和動態網頁技術相結合的方式來構建網站。那些內容相對固定或者剛被使用者瀏覽過的網頁可以採用靜態技術提高訪問效率。比如一些htm、css、javascript等。

        所謂靜態頁面,就是在客戶端傳送請求後,伺服器接收請求並且從請求頭中解析出使用者想要訪問資源的url,然後伺服器根據該url檢索其下對應的靜態頁面htm,最後以流的方式讀取htm的內容寫回給客戶端瀏覽器進行顯示。在整個請求--響應過程中,伺服器端除了做基本的url定位資源和讀取資源內容並寫回給客戶端瀏覽器外,不做其他任何操作。比如:與資料庫伺服器的互動、邏輯運算、Servlet請求轉發等。

2靜態頁面構建

        大家應該都使用過Tomcat,開啟其目錄可以看到,有一個名為webapps的資料夾,該資料夾下放置的是我們編譯後的web工程(.class檔案,Java就是靠它實現cross-platform的),另外還有一個叫做ROOT的子資料夾,用於存放Tomcat的一些靜態頁面和配置檔案。這便是我們要模仿的架構^_^。

2.1在TomJetty工程根目錄下新建一個webapps資料夾

2.2在tomjetty.config檔案中,新增一條配置資訊

tomjetty.webapps=./webapps

2.3修改TomJetty類的run()方法。實現從HTTP請求頭中解析出url,再結合配置檔案中靜態頁面的存放目錄定位到htm,然後將htm內容讀取出來並寫回給客戶端瀏覽器進行顯示

    @Override
    public void run() {
        InputStream in = null;
        OutputStream out = null;
        FileInputStream fin = null;
        try {
            in = socket.getInputStream(); // 獲取客戶端傳送的位元組流
            out = socket.getOutputStream(); // 獲取服務端響應的位元組流
            byte[] b = new byte[1024 * 1024]; // 設定位元組緩衝區
            in.read(b); // 讀取客戶端位元組流(位元組流的請求頭)
            String txt = new String(b).trim(); // 將請求頭封裝成String,準備交給解析器解析
            IReqestHeaderParser parser = (IReqestHeaderParser) Class.forName(
                    TomJettyUtil.getValue("tomjetty.requestheader.class"))
                    .newInstance(); // 使用工廠設計模式從tomjetty.config中載入請求頭解析器的例項
            RequestHeader header = parser.parse(txt); // 解析請求頭文字,使用RequestHeader封裝其內容
//            System.out.println(header);
            File html = new File(TomJettyUtil.getValue("tomjetty.webapps"),
                    header.getUrl()); // 從配置檔案檢索服務端靜態頁面存放目錄,定位到伺服器端的靜態頁面
            fin = new FileInputStream(html);
            byte[] buf = new byte[(int) html.length()];
            fin.read(buf); // 讀取靜態頁面內容
            out.write(buf); // 將靜態頁面內容寫回給客戶端瀏覽器顯示
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (fin != null) {
                    fin.close();
                }
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
                if (socket != null) {
                    socket.close();
                }
            } catch (IOException e) {
            }
        }
    }

2.4提供一些靜態頁面(含有中文、英文、圖片內容的htm)存放於webapps目錄下

        完成後的webapps目錄看起來像下面這樣:


3構建效果展示

3.1英文內容顯示


3.2中文內容顯示


3.3圖片內容顯示

        請求靜態頁面的功能我們已經完成了,但是這樣的請求靜態頁面與真實情況還是有一定差距的。因為請求沒有攜帶使用者引數哦,而且提交請求的方式有GET和POST兩種(咱不考慮Web Service的PUT和DELETE)。所以下一節我們將擴充套件RequestHeader類,使它在GET和POST兩種請求提交方式下都能夠儲存使用者請求的引數。