注:本段內容來源於《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)。
HTTP服務器至少應該實現GET和HEAD方法,其他方法都是可選的。當然,所有的方法支持的實現都應當符合下述的方法各自的語義定義。此外,除了上述方法,特定的HTTP服務器還能夠擴展自定義的方法。
一個簡單的Java web服務器實現
注:本段內容來源於《一個簡單的Java web服務器實現》
前言
一個簡單的Java web服務器實現,比較簡單,基於java.net.Socket和java.net.ServerSocket實現;
程序執行步驟
- 創建一個ServerSocket對象;
- 調用ServerSocket對象的accept方法,等待連接,連接成功會返回一個Socket對象,否則一直阻塞等待;
- 從Socket對象中獲取InputStream和OutputStream字節流,這兩個流分別對應request請求和response響應;
- 處理請求:讀取InputStream字節流信息,轉成字符串形式,並解析,這里的解析比較簡單,僅僅獲取uri(統一資源標識符)信息;
- 處理響應:根據解析出來的uri信息,從WEB_ROOT目錄中尋找請求的資源資源文件, 讀取資源文件,並將其寫入到OutputStream字節流中;
- 關閉Socket對象;
- 轉到步驟2,繼續等待連接請求;
代碼實現
服務器實現:
package ex01.pyrmont; import java.net.Socket; import java.net.ServerSocket; import java.net.InetAddress; import java.io.InputStream; import java.io.OutputStream; import java.io.IOException; import java.io.File; public class HttpServer { /** * WEB_ROOT是HTML和其它文件存放的目錄. 這里的WEB_ROOT為工作目錄下的webroot目錄 */ public static final String WEB_ROOT = System.getProperty("user.dir") + File.separator + "webroot"; // 關閉服務命令 private static final String SHUTDOWN_COMMAND = "/SHUTDOWN"; public static void main(String[] args) { HttpServer server = new HttpServer(); //等待連接請求 server.await(); } public void await() { ServerSocket serverSocket = null; int port = 8080; try { //服務器套接字對象 serverSocket = new ServerSocket(port, 1, InetAddress.getByName("127.0.0.1")); } catch (IOException e) { e.printStackTrace(); System.exit(1); } // 循環等待一個請求 while (true) { Socket socket = null; InputStream input = null; OutputStream output = null; try { //等待連接,連接成功后,返回一個Socket對象 socket = serverSocket.accept(); input = socket.getInputStream(); output = socket.getOutputStream(); // 創建Request對象並解析 Request request = new Request(input); request.parse(); // 檢查是否是關閉服務命令 if (request.getUri().equals(SHUTDOWN_COMMAND)) { break; } // 創建 Response 對象 Response response = new Response(output); response.setRequest(request); response.sendStaticResource(); // 關閉 socket 對象 socket.close(); } catch (Exception e) { e.printStackTrace(); continue; } } } }
Request類:
package ex01.pyrmont; import java.io.InputStream; import java.io.IOException; public class Request { private InputStream input; private String uri; public Request(InputStream input) { this.input = input; } //從InputStream中讀取request信息,並從request中獲取uri值 public void parse() { 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()); } /** * * requestString形式如下: * GET /index.html HTTP/1.1 * Host: localhost:8080 * Connection: keep-alive * Cache-Control: max-age=0 * ... * 該函數目的就是為了獲取/index.html字符串 */ 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; } public String getUri() { return uri; } }
Response類:
package ex01.pyrmont; import java.io.OutputStream; import java.io.IOException; import java.io.FileInputStream; import java.io.File; /* HTTP Response = Status-Line *(( general-header | response-header | entity-header ) CRLF) CRLF [ message-body ] Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF */ public class Response { private static final int BUFFER_SIZE = 1024; Request request; OutputStream output; public Response(OutputStream output) { this.output = output; } public void setRequest(Request request) { this.request = request; } public void sendStaticResource() throws IOException { byte[] bytes = new byte[BUFFER_SIZE]; FileInputStream fis = null; try { //將web文件寫入到OutputStream字節流中 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(); } } }
現在在webroot中創建一個html頁面,命名為index.html,源碼如下:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> <h1>Hello World!</h1> </body> </html>
現在啟動該WEB服務器,並請求index.html靜態頁面。
所對應的控制台的輸出:
如此,一個簡單的http服務器便完成了。