基於JAVA的WEB伺服器工作機制(3)完

來源:互聯網
上載者:User
Request

Request類代表一個HTTP請求。Socket處理用戶端的通訊,將返回一個InputStream對象,通過傳遞該對象,可以構造一個Request類的執行個體。通過調用InputStream 對象的read方法來獲得這個HTTP請求的未經處理資料(raw data)。

Request 有兩個公用方法:parse 和 getUri。parse方法解釋HTTP請求的未經處理資料。它不做很多事情----它能夠利用的唯一資訊只是HTTP請求的URI ,這個URI是從私人方法 parseUri.得到的。parseUri 方法儲存URI 到uri 變數中,然後調用公用方法getUri來返回一個HTTP請求的URI。

為了理解parse 和 parseUri 方法是如何工作的,需要知道HTTP請求的內部結構。這個結構是在RFC2616文檔中定義的。

一個HTTP請求包含三個部分:

  • 請求行(Request line)
  • 請求包頭(Headers)
  • 訊息體(Message body)

現在,我們僅僅只對HTTP請求的第一部分請求行(Request line)感興趣。一個請求行由方法標記開始,後面根請求的URI和協議版本,最後由CRLF字元結束。請求行中的元素被空白字元分開。比如,使用GET方法請求的index.html檔案的請求行如下:

GET /index.html HTTP/1.1 //這是一個請求行

方法parse從socket的InputStream 中讀取整個位元組流,該位元組流是 Request 對象傳遞進來的,然後parse將這些位元組流儲存在一個緩衝區裡, 在緩衝區中組裝一個稱為request的StringBuffer對象。

下面的Listing 1.2.顯示了parse方法的用法:

Listing 1.2. The Request class' parse method

public void parse() {    // Read a set of characters from the socket    StringBuffer request = new StringBuffer(2048);    int i;    byte[] buffer = new byte[2048];    try {        i = input.read(buffer);    }    catch (IOException e) {        e.printStackTrace();        i = -1;    }    for (int j=0; j<i; j++) {        request.append((char) buffer[j]);    }    System.out.print(request.toString());    uri   = parseUri(request.toString());}

parseUri 方法從請求行那裡得到URI。Listing 1.3 展示了parseUri 方法的用途。 parseUri 減縮請求中的第一個和第二個空格來獲得URI。

Listing 1.3. The Request class' parseUri method

private String parseUri(String requestString) {    int index1, index2;    index1 = requestString.indexOf(' ');    if (index1 != -1) {        index2 = requestString.indexOf(' ', index1 + 1);        if (index2 > index1)           return requestString.substring(index1 + 1, index2);    }    return null;}
Response

Response表示一個HTTP響應。它的建構函式接受一個OutputStream對象,比如下面的:

public Response(OutputStream output) {    this.output = output;}

Response 對象被HttpServer類的await方法構造,該方法被傳遞的參數是從socket那裡得到的OutputStream對象。

Response類有兩個公用方法: setRequestsendStaticResource. setRequest方法傳遞一個Request對象給Response對象。Listing 1.4中的代碼顯示了這個:

Listing 1.4. The Response class' setRequest method

public void setRequest(Request request) {    this.request = request;}

sendStaticResource 方法用來發送一個靜態資源,比如HTML檔案。Listing 1.5給出了它的實現過程:

Listing 1.5. The Response class' sendStaticResource method

public void sendStaticResource() throws IOException {    byte[] bytes        = new byte[BUFFER_SIZE];    FileInputStream fis = null;    try {        File file  = new File(HttpServer.WEB_ROOT, request.getUri());        if (file.exists()) {            fis    = new FileInputStream(file);            int ch = fis.read(bytes, 0, BUFFER_SIZE);            while (ch != -1) {                output.write(bytes, 0, ch);                ch = fis.read(bytes, 0, BUFFER_SIZE);            }        }        else {            // file not found            String errorMessage = "HTTP/1.1 404 File Not Found/r/n" +                "Content-Type: text/html/r/n" +                "Content-Length: 23/r/n" +                "/r/n" +                "<h1>File Not Found</h1>";            output.write(errorMessage.getBytes());        }    }    catch (Exception e) {        // thrown if cannot instantiate a File object        System.out.println(e.toString() );    }    finally {        if (fis != null)            fis.close();    }}

sendStaticResource 方法是非常簡單的。它首先傳遞父路徑和子路徑給File類的構造器,從而對java.io.File類進行了執行個體化。

File file = new File(HttpServer.WEB_ROOT, request.getUri());

然後它檢查檔案是否存在。如果存在,sendStaticResource 方法通過傳遞File對象來構造一個java.io.FileInputStream對象。然後調用FileInputStream 的read方法,將位元組流寫如到OutputStream輸出。注意這種情況下, 靜態資源的內容也被作為未經處理資料被發送給了瀏覽器。

if (file.exists()) {    fis    = new FileInputStream(file);    int ch = fis.read(bytes, 0, BUFFER_SIZE);    while (ch != -1) {        output.write(bytes, 0, ch);        ch = fis.read(bytes, 0, BUFFER_SIZE);    }}

如果這個檔案不存在,sendStaticResource 方法發送一個錯誤訊息給瀏覽器。

String errorMessage = "HTTP/1.1 404 File Not Found/r/n" +    "Content-Type: text/html/r/n" +    "Content-Length: 23/r/n" +    "/r/n" +    "<h1>File Not Found</h1>";output.write(errorMessage.getBytes());
編譯和運行應用程式

為了編譯和運行應用,你首先需要解壓包含本文應用程式的.zip檔案。你解壓的目錄成為工作目錄(working directory),它有三個子目錄: src/, classes/, 和 lib/。 要編譯應用程式需要在工作目錄輸入如下語句:

javac -d . src/ex01/pyrmont/*.java

這個-d 選項參數將結果寫到目前的目錄,而不是src/ 目錄。

要運行應用程式,在工作目錄中輸入如下語句:

java ex01.pyrmont.HttpServer

要測試你的應用程式,開啟瀏覽器,在地址欄中輸入如下URL:

http://localhost:8080/index.html

你將可以看到瀏覽器中顯示的index.html 頁面,如Figure 1所示。


Figure 1. The output from the web server

在控制台(Console),你能看到如下內容:

GET /index.html HTTP/1.1Accept: */*Accept-Language: en-usAccept-Encoding: gzip, deflateUser-Agent: Mozilla/4.0 (compatible; MSIE 4.01; Windows 98) Host: localhost:8080Connection: Keep-AliveGET /images/logo.gif HTTP/1.1Accept: */*Referer: http://localhost:8080/index.htmlAccept-Language: en-usAccept-Encoding: gzip, deflateUser-Agent: Mozilla/4.0 (compatible; MSIE 4.01; Windows 98) Host: localhost:8080Connection: Keep-Alive
概要總結

在本文中,你瞭解了一個簡單的WEB伺服器的工作機制。本文附帶的應用程式原始碼只包含三個類,但並不是所有的都有用。儘管如此,它還是能被作為一種很好的學習工具為我們服務。

Translated by Willpower,2003.11.24

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.