關於JAVA的HTTP服務器的簡單實現,還望大家給出寶貴建議,謝謝。
1、首先來說下HTTP所有的狀態碼,相信對於網頁開發的博友們,肯定不陌生。
狀態碼
|
狀態碼英文名稱
|
中文描述
|
---|---|---|
100
|
Continue
|
繼續。
客戶端應繼續其請求
|
101
|
Switching Protocols
|
切換協議。服務器根據客戶端的請求切換協議。只能切換到更高級的協議,例如,切換到HTTP的新版本協議
|
200
|
OK
|
請求成功。一般用於GET與POST請求
|
201
|
Created
|
已創建。成功請求並創建了新的資源
|
202
|
Accepted
|
已接受。已經接受請求,但未處理完成
|
203
|
Non-Authoritative Information
|
非授權信息。請求成功。但返回的meta信息不在原始的服務器,而是一個副本
|
204
|
No Content
|
無內容。服務器成功處理,但未返回內容。在未更新網頁的情況下,可確保瀏覽器繼續顯示當前文檔
|
205
|
Reset Content
|
重置內容。服務器處理成功,用戶終端(例如:瀏覽器)應重置文檔視圖。可通過此返回碼清除瀏覽器的表單域
|
206
|
Partial Content
|
部分內容。服務器成功處理了部分GET請求
|
300
|
Multiple Choices
|
多種選擇。請求的資源可包括多個位置,相應可返回一個資源特征與地址的列表用於用戶終端(例如:瀏覽器)選擇
|
301
|
Moved Permanently
|
永久移動。請求的資源已被永久的移動到新URI,返回信息會包括新的URI,瀏覽器會自動定向到新URI。今后任何新的請求都應使用新的URI代替
|
302
|
Found
|
臨時移動。與301類似。但資源只是臨時被移動。客戶端應繼續使用原有URI
|
303
|
See Other
|
查看其它地址。與301類似。使用GET和POST請求查看
|
304
|
Not Modified
|
未修改。所請求的資源未修改,服務器返回此狀態碼時,不會返回任何資源。客戶端通常會緩存訪問過的資源,通過提供一個頭信息指出客戶端希望只返回在指定日期之后修改的資源
|
305
|
Use Proxy
|
使用代理。所請求的資源必須通過代理訪問
|
306
|
Unused
|
已經被廢棄的HTTP狀態碼
|
307
|
Temporary Redirect
|
臨時重定向。與302類似。使用GET請求重定向
|
400
|
Bad Request
|
客戶端請求的語法錯誤,服務器無法理解
|
401
|
Unauthorized
|
請求要求用戶的身份認證
|
402
|
Payment Required
|
保留,將來使用
|
403
|
Forbidden
|
服務器理解請求客戶端的請求,但是拒絕執行此請求
|
404
|
Not Found
|
服務器無法根據客戶端的請求找到資源(網頁)。通過此代碼,網站設計人員可設置"您所請求的資源無法找到"的個性頁面
|
405
|
Method Not Allowed
|
客戶端請求中的方法被禁止
|
406
|
Not Acceptable
|
服務器無法根據客戶端請求的內容特性完成請求
|
407
|
Proxy Authentication Required
|
請求要求代理的身份認證,與401類似,但請求者應當使用代理進行授權
|
408
|
Request Time-out
|
服務器等待客戶端發送的請求時間過長,超時
|
409
|
Conflict
|
服務器完成客戶端的PUT請求時可能返回此代碼,服務器處理請求時發生了沖突
|
410
|
Gone
|
客戶端請求的資源已經不存在。410不同於404,如果資源以前有現在被永久刪除了可使用410代碼,網站設計人員可通過301代碼指定資源的新位置
|
411
|
Length Required
|
服務器無法處理客戶端發送的不帶Content-Length的請求信息
|
412
|
Precondition Failed
|
客戶端請求信息的先決條件錯誤
|
413
|
Request Entity Too Large
|
由於請求的實體過大,服務器無法處理,因此拒絕請求。為防止客戶端的連續請求,服務器可能會關閉連接。如果只是服務器暫時無法處理,則會包含一個Retry-After的響應信息
|
414
|
Request-URI Too Large
|
請求的URI過長(URI通常為網址),服務器無法處理
|
415
|
Unsupported Media Type
|
服務器無法處理請求附帶的媒體格式
|
416
|
Requested range not satisfiable
|
客戶端請求的范圍無效
|
417
|
Expectation Failed
|
服務器無法滿足Expect的請求頭信息
|
500
|
Internal Server Error
|
服務器內部錯誤,無法完成請求
|
501
|
Not Implemented
|
服務器不支持請求的功能,無法完成請求
|
502
|
Bad Gateway
|
充當網關或代理的服務器,從遠端服務器接收到了一個無效的請求
|
503
|
Service Unavailable
|
由於超載或系統維護,服務器暫時的無法處理客戶端的請求。延時的長度可包含在服務器的Retry-After頭信息中
|
504
|
Gateway Time-out
|
充當網關或代理的服務器,未及時從遠端服務器獲取請求
|
505
|
HTTP Version not supported
|
服務器不支持請求的HTTP協議的版本,無法完成處理
|
2、其次,在講解一下關於HTTP響應頭:
響應頭
客戶端向服務器發送一個請求,服務器以一個狀態行作為響應,響應的內容包括:消息協議的版本、成功或者錯誤編碼、服務器信息、實體元信息以及必要的實體內容。根據響應類別的類別,服務器響應里可以含實體內容,但不是所有的響應都有實體內容。本節僅簡述響應頭[13]
。
響應頭第一行
響應頭第一行也稱為狀態行,格式如下:
HTTP-Version 空格 Status-Code 空格 Reason-Phrase CRLF
HTTP- Version表示HTTP版本,例如為HTTP/1.1。Status- Code是結果代碼,用三個數字表示。Reason-Phrase是個簡單的文本描述,解釋Status-Code的具體原因。Status-Code用於機器自動識別,Reason-Phrase用於人工理解。Status-Code的第一個數字代表響應類別,可能取5個不同的值。后兩個數字沒有分類作用。Status-Code的第一個數字代表響應的類別,后續兩位描述在該類響應下發生的具體狀況,具體請參見:
HTTP狀態碼 。
3、還有關於HTTP的請求方法:
請求方法
HTTP/1.1協議中共定義了八種方法(有時也叫“動作”)來表明Request-URI指定的資源的不同操作方式:
OPTIONS - 返回服務器針對特定資源所支持的HTTP請求方法。也可以利用向Web服務器發送'*'的請求來測試服務器的功能性。
HEAD- 向服務器索要與GET請求相一致的響應,只不過響應體將不會被返回。這一方法可以在不必傳輸整個響應內容的情況下,就可以獲取包含在響應消息頭中的元信息。
GET - 向特定的資源發出請求。注意:GET方法不應當被用於產生“副作用”的操作中,例如在web app.中。其中一個原因是GET可能會被
網絡蜘蛛等隨意訪問。
POST - 向指定資源提交數據進行處理請求(例如提交表單或者上傳文件)。數據被包含在請求體中。POST請求可能會導致新的資源的建立和/或已有資源的修改。
PUT - 向指定資源位置上傳其最新內容。
DELETE - 請求服務器刪除Request-URI所標識的資源。
TRACE- 回顯服務器收到的請求,主要用於測試或診斷。
CONNECT - HTTP/1.1協議中預留給能夠將連接改為管道方式的
代理服務器。
PATCH - 用來將局部修改應用於某一資源,添加於規范RFC5789。
方法名稱是區分大小寫的。當某個請求所針對的資源不支持對應的請求方法的時候,服務器應當返回狀態碼405(Method Not Allowed);當服務器不認識或者不支持對應的請求方法的時候,應當返回狀態碼501(Not Implemented)。
package demo.server; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; public class HTTPServer { public static void main(String[] args) { try { ServerSocket ss=new ServerSocket(8888); while(true){ Socket socket=ss.accept(); BufferedReader bd=new BufferedReader(new InputStreamReader(socket.getInputStream())); /** * 接受HTTP請求 */ String requestHeader; int contentLength=0; while((requestHeader=bd.readLine())!=null&&!requestHeader.isEmpty()){ System.out.println(requestHeader); /** * 獲得GET參數 */ if(requestHeader.startsWith("GET")){ int begin = requestHeader.indexOf("/?")+2; int end = requestHeader.indexOf("HTTP/"); String condition=requestHeader.substring(begin, end); System.out.println("GET參數是:"+condition); } /** * 獲得POST參數 * 1.獲取請求內容長度 */ if(requestHeader.startsWith("Content-Length")){ int begin=requestHeader.indexOf("Content-Lengh:")+"Content-Length:".length(); String postParamterLength=requestHeader.substring(begin).trim(); contentLength=Integer.parseInt(postParamterLength); System.out.println("POST參數長度是:"+Integer.parseInt(postParamterLength)); } } StringBuffer sb=new StringBuffer(); if(contentLength>0){ for (int i = 0; i < contentLength; i++) { sb.append((char)bd.read()); } System.out.println("POST參數是:"+sb.toString()); } //發送回執 PrintWriter pw=new PrintWriter(socket.getOutputStream()); pw.println("HTTP/1.1 200 OK"); pw.println("Content-type:text/html"); pw.println(); pw.println("<h1>訪問成功!</h1>"); pw.flush(); socket.close(); } } catch (IOException e) { e.printStackTrace(); } } }
本示例實現了僅為簡單是實現,其中不足還望見諒。