1**:請求收到,繼續處理
2**:操作成功收到,分析、接受
3**:完成此請求必須進一步處理
4**:請求包含一個錯誤語法或不能完成
5**:服務器執行一個完全有效請求失敗
100——客戶必須繼續發出請求
101——客戶要求服務器根據請求轉換HTTP協議版本
200——交易成功
201——提示知道新文件的URL
202——接受和處理、但處理未完成
203——返回信息不確定或不完整
204——請求收到,但返回信息為空
205——服務器完成了請求,用戶代理必須復位當前已經瀏覽過的文件
206——服務器已經完成了部分用戶的GET請求
300——請求的資源可在多處得到
301——刪除請求數據
302——在其他地址發現了請求數據
303——建議客戶訪問其他URL或訪問方式
304——客戶端已經執行了GET,但文件未變化
305——請求的資源必須從服務器指定的地址得到
306——前一版本HTTP中使用的代碼,現行版本中不再使用
307——申明請求的資源臨時性刪除
400——錯誤請求,如語法錯誤
401——請求授權失敗
402——保留有效ChargeTo頭響應
403——請求不允許
404——沒有發現文件、查詢或URl
405——用戶在Request-Line字段定義的方法不允許
406——根據用戶發送的Accept拖,請求資源不可訪問
407——類似401,用戶必須首先在代理服務器上得到授權
408——客戶端沒有在用戶指定的餓時間內完成請求
409——對當前資源狀態,請求不能完成
410——服務器上不再有此資源且無進一步的參考地址
411——服務器拒絕用戶定義的Content-Length屬性請求
412——一個或多個請求頭字段在當前請求中錯誤
413——請求的資源大于服務器允許的大小
414——請求的資源URL長于服務器允許的長度
415——請求資源不支持請求項目格式
416——請求中包含Range請求頭字段,在當前請求資源范圍內沒有range指示值,請求
也不包含If-Range請求頭字段
417——服務器不滿足請求Expect頭字段指定的期望值,如果是代理服務器,可能是下
一級服務器不能滿足請求
500——服務器產生內部錯誤
501——服務器不支持請求的函數
502——服務器暫時不可用,有時是為了防止發生系統過載
503——服務器過載或暫停維修
504——關口過載,服務器使用另一個關口或服務來響應用戶,等待時間設定值較長
505——服務器不支持或拒絕支請求頭中指定的HTTP版本
==========================================================
英文版:
100:Continue
101:Switching Protocols
102:Processing
200:OK
201:Created
202:Accepted
203:Non-Authoriative Information
204:No Content
205:Reset Content
206:Partial Content
207:Multi-Status
300:Multiple Choices
301:Moved Permanently
302:Found
303:See Other
304:Not Modified
305:Use Proxy
306:(Unused)
307:Temporary Redirect
400:Bad Request
401:Unauthorized
402:Payment Granted
403:Forbidden
404:File Not Found
405:Method Not Allowed
406:Not Acceptable
407:Proxy Authentication Required
408:Request Time-out
409:Conflict
410:Gone
411:Length Required
412:Precondition Failed
413:Request Entity Too Large
414:Request-URI Too Large
415:Unsupported Media Type
416:Requested range not satisfiable
417:Expectation Failed
422:Unprocessable Entity
423:Locked
424:Failed Dependency
500:Internal Server Error
501:Not Implemented
502:Bad Gateway
503:Service Unavailable
504:Gateway Timeout
505:HTTP Version Not Supported
507:Insufficient Storage
完整的 HTTP 1.1規范說明書來自于RFC 2616,你可以在rfc-editor在線查閱。HTTP 1.1的狀態碼被標記為新特性,因為許多瀏覽器只支持 HTTP 1.0。你應只把狀態碼發送給支持 HTTP 1.1的客戶端,支持協議版本可以通過調用request.getRequestProtocol來檢查。
本部分余下的內容會詳細地介紹 HTTP 1.1中的狀態碼。這些狀態碼被分為五大類:
100-199 用于指定客戶端應相應的某些動作。
200-299 用于表示請求成功。
300-399 用于已經移動的文件并且常被包含在定位頭信息中指定新的地址信息。
400-499 用于指出客戶端的錯誤。
500-599 用于支持服務器錯誤。
HttpServletResponse中的常量代表關聯不同標準消息的狀態碼。在servlet程序中,你會更多地用到這些常量的標識來使用狀態碼。例如:你一般會使用response.setStatus(response.SC_NO_CONTENT)而不是 response.setStatus(204),因為后者不易理解而且容易導致錯誤。但是,你應當注意到服務器允許對消息輕微的改變,而客戶端只注意狀態碼的數字值。所以服務器可能只返回 HTTP/1.1 200 而不是 HTTP/1.1 200 OK。
100 (Continue/繼續)
如果服務器收到頭信息中帶有100-continue的請求,這是指客戶端詢問是否可以在后續的請求中發送附件。在這種情況下,服務器用100(SC_CONTINUE)允許客戶端繼續或用417 (Expectation Failed)告訴客戶端不同意接受附件。這個狀態碼是 HTTP 1.1中新加入的。
101 (Switching Protocols/轉換協議)
101 (SC_SWITCHING_PROTOCOLS)狀態碼是指服務器將按照其上的頭信息變為一個不同的協議。這是 HTTP 1.1中新加入的。
200 (OK/正常)
200 (SC_OK)的意思是一切正常。一般用于相應GET和POST請求。這個狀態碼對servlet是缺省的;如果沒有調用setStatus方法的話,就會得到200。
201 (Created/已創建)
201 (SC_CREATED)表示服務器在請求的響應中建立了新文檔;應在定位頭信息中給出它的URL。
202 (Accepted/接受)
202 (SC_ACCEPTED)告訴客戶端請求正在被執行,但還沒有處理完。
203 (Non-Authoritative Information/非官方信息)
狀態碼203 (SC_NON_AUTHORITATIVE_INFORMATION)是表示文檔被正常的返回,但是由于正在使用的是文檔副本所以某些響應頭信息可能不正確。這是 HTTP 1.1中新加入的。
204 (No Content/無內容)
在并沒有新文檔的情況下,204 (SC_NO_CONTENT)確保瀏覽器繼續顯示先前的文檔。這各狀態碼對于用戶周期性的重載某一頁非常有用,并且你可以確定先前的頁面是否已經更新。例如,某個servlet可能作如下操作:
int pageVersion =Integer.parseInt(request.getParameter("pageVersion"));
if (pageVersion >;= currentVersion) {
response.setStatus(response.SC_NO_CONTENT);
} else {
// Create regular page
}
但是,這種方法對通過刷新響應頭信息或等價的HTML標記自動重載的頁面起作用,因為它會返回一個204狀態碼停止以后的重載。但基于JavaScript腳本的自動重載在這種情況下仍然需要能夠起作用??梢蚤喿x本書7.2 ( HTTP 1.1 Response Headers and Their Meaning/HTTP 1.1響應頭信息以及他們的意義)部分的詳細討論。
205 (Reset Content/重置內容)
重置內容205 (SC_RESET_CONTENT)的意思是雖然沒有新文檔但瀏覽器要重置文檔顯示。這個狀態碼用于強迫瀏覽器清除表單域。這是 HTTP 1.1中新加入的。
206 (Partial Content/局部內容)
206 (SC_PARTIAL_CONTENT)是在服務器完成了一個包含Range頭信息的局部請求時被發送的。這是 HTTP 1.1中新加入的。
300 (Multiple Choices/多重選擇)
300 (SC_MULTIPLE_CHOICES)表示被請求的文檔可以在多個地方找到,并將在返回的文檔中列出來。如果服務器有首選設置,首選項將會被列于定位響應頭信息中。
301 (Moved Permanently)
301 (SC_MOVED_PERMANENTLY)狀態是指所請求的文檔在別的地方;文檔新的URL會在定位響應頭信息中給出。瀏覽器會自動連接到新的URL。
302 (Found/找到)
與301有些類似,只是定位頭信息中所給的URL應被理解為臨時交換地址而不是永久的。注意:在 HTTP 1.0中,消息是臨時移動(Moved Temporarily)的而不是被找到,因此HttpServletResponse中的常量是SC_MOVED_TEMPORARILY不是我們以為的SC_FOUND。
注意
代表狀態碼302的常量是SC_MOVED_TEMPORARILY而不是SC_FOUND。
狀態碼302是非常有用的因為瀏覽器自動連接在定為響應頭信息中給出的新URL。這非常有用,而且為此有一個專門的方法——sendRedirect。使用response.sendRedirect(url)比調用response.setStatus(response.SC_MOVED_TEMPORARILY)和response.setHeader("Location", url)多幾個好處。首先,response.sendRedirect(url)方法明顯要簡單和容易。第二,servlet自動建立一頁保存這一連接以提供給那些不能自動轉向的瀏覽器顯示。最后,在servlet 2.2版本(J2EE中的版本)中,sendRedirect能夠處理相對路徑,自動轉換為絕對路徑。但是你只能在2.1版本中使用絕對路徑。
如果你將用戶轉向到站點的另一頁中,你要用 HttpServletResponse 中的 encodeURL 方法傳送URL。這么做可預防不斷使用基于URL重寫的會話跟蹤的情況。URL重寫是一種在你的網站跟蹤不使用 cookies 的用戶的方法。這是通過在每一個URL尾部附加路徑信息實現的,但是 servlet 會話跟蹤API會自動的注意這些細節。會話跟蹤在第九章討論,并且養成使用 encodeURL 的習慣會使以后添加會話跟蹤的功能更容易很多。
核心技巧
如果你將用戶轉向到你的站點的其他頁面,用 response.sendRedirect(response.encodeURL(url)) 的方式事先計劃好會話跟蹤(session tracking)要比只是調用 response.sendRedirect(url) 好的多。
這個狀態碼有時可以與301交換使用。例如,如果你錯誤的訪問了某路徑信息不完整),有些服務器就會回復301狀態碼而有些則回復302。從技術上說,如果最初的請求是GET瀏覽器只是被假定自動轉向。如果想了解更多細節,請看狀態碼307的討論。
303 (See Other/參見其他信息)
這個狀態碼和 301、302 相似,只是如果最初的請求是 POST,那么新文檔(在定位頭信息中給出)藥用 GET 找回。這個狀態碼是新加入 HTTP 1.1中的。
304 (Not Modified/為修正)
當客戶端有一個緩存的文檔,通過提供一個 If-Modified-Since 頭信息可指出客戶端只希望文檔在指定日期之后有所修改時才會重載此文檔,用這種方式可以進行有條件的請求。304 (SC_NOT_MODIFIED)是指緩沖的版本已經被更新并且客戶端應刷新文檔。另外,服務器將返回請求的文檔及狀態碼 200。servlet一般情況下不會直接設置這個狀態碼。它們會實現getLastModified方法并根據修正日期讓默認服務方法處理有條件的請求。這個方法的例程已在2.8部分(An Example Using Servlet Initialization and Page Modification Dates/一個使用servlet初始化和頁面修正日期的例子)給出。
305 (Use Proxy/使用代理)
305 (SC_USE_PROXY)表示所請求的文檔要通過定位頭信息中的代理服務器獲得。這個狀態碼是新加入 HTTP 1.1中的。
307 (Temporary Redirect/臨時重定向)
瀏覽器處理307狀態的規則與302相同。307狀態被加入到 HTTP 1.1中是由于許多瀏覽器在收到302響應時即使是原始消息為POST的情況下仍然執行了錯誤的轉向。只有在收到303響應時才假定瀏覽器會在POST請求時重定向。添加這個新的狀態碼的目的很明確:在響應為303時按照GET和POST請求轉向;而在307響應時則按照GET請求轉向而不是POST請求。注意:由于某些原因在HttpServletResponse中還沒有與這個狀態對應的常量。該狀態碼是新加入HTTP 1.1中的。
注意
在 HttpServletResponse 中沒有 SC_TEMPORARY_REDIRECT 常量,所以你只能顯示的使用307狀態碼。
400 (Bad Request/錯誤請求)
400 (SC_BAD_REQUEST)指出客戶端請求中的語法錯誤。
401 (Unauthorized/未授權)
401 (SC_UNAUTHORIZED)表示客戶端在授權頭信息中沒有有效的身份信息時訪問受到密碼保護的頁面。這個響應必須包含一個WWW-Authenticate的授權信息頭。例如,在本書4.5部分中的“Restricting Access to Web Pages./限制訪問Web頁?!?
403 (Forbidden/禁止)
403 (SC_FORBIDDEN)的意思是除非擁有授權否則服務器拒絕提供所請求的資源。這個狀態經常會由于服務器上的損壞文件或目錄許可而引起。
404 (Not Found/未找到)
404 (SC_NOT_FOUND)狀態每個網絡程序員可能都遇到過,他告訴客戶端所給的地址無法找到任何資源。它是表示“沒有所訪問頁面”的標準方式。這個狀態碼是常用的響應并且在HttpServletResponse類中有專門的方法實現它:sendError("message")。相對于setStatus使用sendError得好處是:服務器會自動生成一個錯誤頁來顯示錯誤信息。但是,Internet Explorer 5瀏覽器卻默認忽略你發揮的錯誤頁面并顯示其自定義的錯誤提示頁面,雖然微軟這么做違反了 HTTP 規范。要關閉此功能,在工具菜單里,選擇Internet選項,進入高級標簽頁,并確認“顯示友好的 HTTP 錯誤信息”選項(在我的瀏覽器中是倒數第8各選項)沒有被選。但是很少有用戶知道此選項,因此這個特性被IE5隱藏了起來使用戶無法看到你所返回給用戶的信息。而其他主流瀏覽器及IE4都完全的顯示服務器生成的錯誤提示頁面??梢詤⒖紙D6-3及6-4中的例子。
核心警告
默認情況下,IE5忽略服務端生成的錯誤提示頁面。
405 (Method Not Allowed/方法未允許)
405 (SC_METHOD_NOT_ALLOWED)指出請求方法(GET, POST, HEAD, PUT, DELETE, 等)對某些特定的資源不允許使用。該狀態碼是新加入 HTTP 1.1中的。
406 (Not Acceptable/無法訪問)
406 (SC_NOT_ACCEPTABLE)表示請求資源的MIME類型與客戶端中Accept頭信息中指定的類型不一致。見本書7.2部分中的表7.1(HTTP 1.1 Response Headers and Their Meaning/HTTP 1.1響應頭信息以及他們的意義)中對MIME類型的介紹。406是新加入 HTTP 1.1中的。
407 (Proxy Authentication Required/代理服務器認證要求)
407 (SC_PROXY_AUTHENTICATION_REQUIRED)與401狀態有些相似,只是這個狀態用于代理服務器。該狀態指出客戶端必須通過代理服務器的認證。代理服務器返回一個Proxy-Authenticate響應頭信息給客戶端,這會引起客戶端使用帶有Proxy-Authorization請求的頭信息重新連接。該狀態碼是新加入 HTTP 1.1中的。
408 (Request Timeout/請求超時)
408 (SC_REQUEST_TIMEOUT)是指服務端等待客戶端發送請求的時間過長。該狀態碼是新加入 HTTP 1.1中的。
409 (Conflict/沖突)
該狀態通常與PUT請求一同使用,409 (SC_CONFLICT)狀態常被用于試圖上傳版本不正確的文件時。該狀態碼是新加入 HTTP 1.1中的。
410 (Gone/已經不存在)
410 (SC_GONE)告訴客戶端所請求的文檔已經不存在并且沒有更新的地址。410狀態不同于404,410是在指導文檔已被移走的情況下使用,而404則用于未知原因的無法訪問。該狀態碼是新加入 HTTP 1.1中的。
411 (Length Required/需要數據長度)
411 (SC_LENGTH_REQUIRED)表示服務器不能處理請求(假設為帶有附件的POST請求),除非客戶端發送Content-Length頭信息指出發送給服務器的數據的大小。該狀態是新加入 HTTP 1.1的。
412 (Precondition Failed/先決條件錯誤)
412 (SC_PRECONDITION_FAILED)狀態指出請求頭信息中的某些先決條件是錯誤的。該狀態是新加入 HTTP 1.1的。
413 (Request Entity Too Large/請求實體過大)
413 (SC_REQUEST_ENTITY_TOO_LARGE)告訴客戶端現在所請求的文檔比服務器現在想要處理的要大。如果服務器認為能夠過一段時間處理,則會包含一個Retry-After的響應頭信息。該狀態是新加入 HTTP 1.1的。
414 (Request URI Too Long/請求URI過長)
414 (SC_REQUEST_URI_TOO_LONG)狀態用于在URI過長的情況時。這里所指的“URI”是指URL中主機、域名及端口號之后的內容。該狀態是新加入 HTTP 1.1的。
415 (Unsupported Media Type/不支持的媒體格式)
415 (SC_UNSUPPORTED_MEDIA_TYPE)意味著請求所帶的附件的格式類型服務器不知道如何處理。該狀態是新加入 HTTP 1.1的。
416 (Requested Range Not Satisfiable/請求范圍無法滿足)
416表示客戶端包含了一個服務器無法滿足的Range頭信息的請求。該狀態是新加入 HTTP 1.1的。奇怪的是,在servlet 2.1版本API的HttpServletResponse中并沒有相應的常量代表該狀態。
注意
在servlet 2.1的規范中,類HttpServletResponse并沒有SC_REQUESTED_RANGE_NOT_SATISFIABLE 這樣的常量,所以你只能直接使用416。在servlet 2.2版本之后都包含了此常量。
417 (Expectation Failed/期望失敗)
如果服務器得到一個帶有100-continue值的Expect請求頭信息,這是指客戶端正在詢問是否可以在后面的請求中發送附件。在這種情況下,服務器也會用該狀態(417)告訴瀏覽器服務器不接收該附件或用100 (SC_CONTINUE)狀態告訴客戶端可以繼續發送附件。該狀態是新加入 HTTP 1.1的。
500 (Internal Server Error/內部服務器錯誤)
500 (SC_INTERNAL_SERVER_ERROR) 是常用的“服務器錯誤”狀態。該狀態經常由CGI程序引起也可能(但愿不會如此!)由無法正常運行的或返回頭信息格式不正確的servlet引起。
501 (Not Implemented/未實現)
501 (SC_NOT_IMPLEMENTED)狀態告訴客戶端服務器不支持請求中要求的功能。例如,客戶端執行了如PUT這樣的服務器并不支持的命令。
502 (Bad Gateway/錯誤的網關)
502 (SC_BAD_GATEWAY)被用于充當代理或網關的服務器;該狀態指出接收服務器接收到遠端服務器的錯誤響應。
503 (Service Unavailable/服務無法獲得)
狀態碼503 (SC_SERVICE_UNAVAILABLE)表示服務器由于在維護或已經超載而無法響應。例如,如果某些線程或數據庫連接池已經沒有空閑則servlet會返回這個頭信息。服務器可提供一個Retry-After頭信息告訴客戶端什么時候可以在試一次。
504 (Gateway Timeout/網關超時)
該狀態也用于充當代理或網關的服務器;它指出接收服務器沒有從遠端服務器得到及時的響應。該狀態是新加入 HTTP 1.1的。
505 (HTTP Version Not Supported/不支持的 HTTP 版本)
505 (SC_HTTP_VERSION_NOT_SUPPORTED)狀態碼是說服務器并不支持在請求中所標明 HTTP 版本。該狀態是新加入 HTTP 1.1的。
HTTP狀態碼
HTTP狀態碼(英語:HTTP Status Code)是用以表示網頁服務器超文本傳輸協議響應狀態的3位數字代碼。它由 RFC 2616 規范定義的,并得到 RFC 2518、RFC 2817、RFC 2295、RFC 2774 與 RFC 4918 等規范擴展。所有狀態碼的第一個數字代表了響應的五種狀態之一。所示的消息短語是典型的,但是可以提供任何可讀取的替代方案。 除非另有說明,狀態碼是HTTP / 1.1標準(RFC 7231)的一部分。
HTTP狀態碼的官方注冊表由互聯網號碼分配局(Internet Assigned Numbers Authority)維護。
微軟互聯網信息服務 (Microsoft Internet Information Services)有時會使用額外的十進制子代碼來獲取更多具體信息,但是這些子代碼僅出現在響應有效內容和文檔中,而不是代替實際的HTTP狀態代碼。
HTTP狀態碼分類
分類 分類描述
1 信息,服務器收到請求,需要請求者繼續執行操作
2 成功,操作被成功接收并處理
3 重定向,需要進一步的操作以完成請求
4 客戶端錯誤,請求包含語法錯誤或無法完成請求
5** 服務器錯誤,服務器在處理請求的過程中發生了錯誤
1xx 信息(消息)
這一類型的狀態碼,代表請求已被接受,需要繼續處理。這類響應是臨時響應,只包含狀態行和某些可選的響應頭信息,并以空行結束。由于 HTTP/1.0 協議中沒有定義任何 1xx 狀態碼,所以除非在某些試驗條件下,服務器禁止向此類客戶端發送 1xx 響應。
100 Continue
繼續??蛻舳藨斃^續發送請求。
101 Switching Protocols
切換協議。服務器根據客戶端的請求切換協議。只能切換到更高級的協議,例如,切換到HTTP的新版本協議。
2xx 成功
這一類型的狀態碼,代表請求已成功被服務器接收、理解、并接受。
200 OK
請求成功。請求所希望的響應頭或數據體將隨此響應返回。出現此狀態碼是表示正常狀態。
201 Created
已創建。成功請求并創建了新的資源。
202 Accepted
已接受。已經接受請求,但未處理完成。
203 Non-Authoritative Information
非授權信息。請求成功,但返回的meta信息不在原始的服務器,而是一個副本。
204 No Content
無內容。服務器成功處理,但未返回內容。在未更新網頁的情況下,可確保瀏覽器繼續顯示當前文檔。
205 Reset Content
重置內容。服務器處理成功,用戶終端(例如:瀏覽器)應重置文檔視圖。可通過此返回碼清除瀏覽器的表單域。
206 Partial Content
部分內容。服務器成功處理了部分GET請求,類似于 FlashGet 或者迅雷這類的 HTTP下載工具都是使用此類響應實現斷點續傳或者將一個大文檔分解為多個下載段同時下載。
3xx 重定向
這類狀態碼代表需要客戶端采取進一步的操作才能完成請求。通常,這些狀態碼用來重定向,后續的請求地址(重定向目標)在本次響應的 Location 域中指明。
當且僅當后續的請求所使用的方法是 GET 或者 HEAD 時,用戶瀏覽器才可以在沒有用戶介入的情況下自動提交所需要的后續請求??蛻舳藨斪詣颖O測無限循環重定向(例如:A->A,或者A->B->C->A),因為這會導致服務器和客戶端大量不必要的資源消耗。按照 HTTP/1.0 版規范的建議,瀏覽器不應自動訪問超過5次的重定向。
300 Multiple Choices
多種選擇。請求的資源可包括多個位置,相應可返回一個資源特征與地址的列表用于用戶終端(例如:瀏覽器)選擇。
301 Moved Permanently
永久移動。請求的資源已被永久的移動到新URI,返回信息會包括新的URI,瀏覽器會自動定向到新URI。今后任何新的請求都應使用新的URI代替。
302 Move Temporarily(Found)
臨時移動。與301類似,但資源只是臨時被移動,客戶端應繼續使用原有URI。
303 See Other
查看其它地址。與301類似,使用GET和POST請求查看。
304 Not Modified
未修改。所請求的資源未修改,服務器返回此狀態碼時,不會返回任何資源??蛻舳送ǔ彺嬖L問過的資源,通過提供一個頭信息指出客戶端希望只返回在指定日期之后修改的資源。
305 Use Proxy
使用代理。所請求的資源必須通過代理訪問。
306 Switch Proxy
在版的規范中,306狀態碼已經不再被使用。它算是已經被廢棄的HTTP狀態碼。
307 Temporary Redirect
臨時重定向。與302類似,使用GET請求重定向。
4xx 客戶端錯誤(請求錯誤)
這類的狀態碼代表了客戶端看起來可能發生了錯誤,妨礙了服務器的處理。除非響應的是一個 HEAD 請求,否則服務器就應該返回一個解釋當前錯誤狀況的實體,以及這是臨時的還是永久性的狀況。這些狀態碼適用于任何請求方法。瀏覽器應當向用戶顯示任何包含在此類錯誤響應中的實體內容。
如果錯誤發生時客戶端正在傳送數據,那么使用TCP的服務器實現應當仔細確保在關閉客戶端與服務器之間的連接之前,客戶端已經收到了包含錯誤信息的數據包。如果客戶端在收到錯誤信息后繼續向服務器發送數據,服務器的TCP棧將向客戶端發送一個重置數據包,以清除該客戶端所有還未識別的輸入緩沖,以免這些數據被服務器上的應用程序讀取并干擾后者。
400 Bad Request
客戶端請求的語法錯誤,服務器無法理解。
401 Unauthorized
當前請求需要用戶驗證。
402 Payment Required
該狀態碼是為了將來可能的需求而預留的。(保留,將來使用。)
403 Forbidden
服務器理解請求客戶端的請求,但是拒絕執行此請求。
404 Not Found
請求失敗,請求所希望得到的資源未被在服務器上發現。沒有信息能夠告訴用戶這個狀況到底是暫時的還是永久的。假如服務器知道情況的話,應當使用410狀態碼來告知舊資源因為某些內部的配置機制問題,已經永久的不可用,而且沒有任何可以跳轉的地址。404這個狀態碼被廣泛應用于當服務器不想揭示到底為何請求被拒絕或者沒有其他適合的響應可用的情況下。出現這個錯誤的最有可能的原因是服務器端沒有這個頁面。
405 Method Not Allowed
客戶端請求中的方法被禁止,也就是請求行中指定的請求方法不能被用于請求相應的資源。該響應必須返回一個Allow 頭信息用以表示出當前資源能夠接受的請求方法的列表。
406 Not Acceptable
服務器無法根據客戶端請求的內容特性完成請求,也就是請求的資源的內容特性無法滿足請求頭中的條件,因而無法生成響應實體。
407 Proxy Authentication Required
與401響應類似,只不過客戶端必須在代理服務器上進行身份驗證。代理服務器必須返回一個 Proxy-Authenticate 用以進行身份詢問。客戶端可以返回一個 Proxy-Authorization 信息頭用以驗證。參見RFC 2617。
408 Request Timeout
請求超時??蛻舳藳]有在服務器預備等待的時間內完成一個請求的發送。客戶端可以隨時再次提交這一請求而無需進行任何更改。
409 Conflict
由于和被請求的資源的當前狀態之間存在沖突,請求無法完成。這個代碼只允許用在這樣的情況下才能被使用:用戶被認為能夠解決沖突,并且會重新提交新的請求。該響應應當包含足夠的信息以便用戶發現沖突的源頭。
沖突通常發生于對 PUT 請求的處理中。例如,在采用版本檢查的環境下,某次 PUT 提交的對特定資源的修改請求所附帶的版本信息與之前的某個(第三方)請求向沖突,那么此時服務器就應該返回一個409錯誤,告知用戶請求無法完成。此時,響應實體中很可能會包含兩個沖突版本之間的差異比較,以便用戶重新提交歸并以后的新版本。
410 Gone
客戶端請求的資源已經不存在。410不同于404,如果資源以前有現在被永久刪除了可使用410代碼,網站設計人員可通過301代碼指定資源的新位置。
411 Length Required
服務器拒絕在沒有定義 Content-Length 頭的情況下接受請求。在添加了表明請求消息體長度的有效 Content-Length 頭之后,客戶端可以再次提交該請求。
412 Precondition Failed
客戶端請求信息的先決條件錯誤,也就是服務器在驗證在請求的頭字段中給出先決條件時,沒能滿足其中的一個或多個。這個狀態碼允許客戶端在獲取資源時在請求的元信息(請求頭字段數據)中設置先決條件,以此避免該請求方法被應用到其希望的內容以外的資源上。
413 Request Entity Too Large
服務器拒絕處理當前請求,因為該請求提交的實體數據大小超過了服務器愿意或者能夠處理的范圍。此種情況下,服務器可以關閉連接以免客戶端繼續發送此請求。
如果這個狀況是臨時的,服務器應當返回一個 Retry-After 的響應頭,以告知客戶端可以在多少時間以后重新嘗試。
414 Request-URI Too Long
請求的URI過長(URI通常為網址),服務器無法處理。
415 Unsupported Media Type
服務器無法處理請求附帶的媒體格式,也就是對于當前請求的方法和所請求的資源,請求中提交的實體并不是服務器中所支持的格式,因此請求被拒絕。
416 Requested Range Not Satisfiable
客戶端請求的范圍無效,也就是如果請求中包含了 Range 請求頭,并且 Range 中指定的任何數據范圍都與當前資源的可用范圍不重合,同時請求中又沒有定義 If-Range 請求頭,那么服務器就應當返回416狀態碼。
417 Expectation Failed
服務器無法滿足Expect的請求頭信息,也就是在請求頭 Expect 中指定的預期內容無法被服務器滿足,或者這個服務器是一個代理服務器,它有明顯的證據證明在當前路由的下一個節點上,Expect 的內容無法被滿足。
5xx 服務器錯誤
這類狀態碼代表了服務器在處理請求的過程中有錯誤或者異常狀態發生,也有可能是服務器意識到以當前的軟硬件資源無法完成對請求的處理。除非這是一個HEAD 請求,否則服務器應當包含一個解釋當前錯誤狀態以及這個狀況是臨時的還是永久的解釋信息實體。瀏覽器應當向用戶展示任何在當前響應中被包含的實體。這些狀態碼適用于任何響應方法。
500 Internal Server Error
服務器內部錯誤,無法完成請求。服務器遇到了一個未曾預料的狀況,導致了它無法完成對請求的處理。一般來說,這個問題都會在服務器端的源代碼出現錯誤時出現。
501 Not Implemented
服務器不支持當前請求所需要的某個功能。當服務器無法識別請求的方法,并且無法支持其對任何資源的請求。
502 Bad Gateway
作為網關或者代理工作的服務器嘗試執行請求時,從遠程服務器接收到了一個無效的響應。
503 Service Unavailable
由于臨時的服務器維護或者過載,服務器當前無法處理請求。這個狀況是臨時的,并且將在一段時間以后恢復。如果能夠預計延遲時間,那么響應中可以包含一個 Retry-After 頭用以標明這個延遲時間。如果沒有給出這個 Retry-After 信息,那么客戶端應當以處理500響應的方式處理它。
注意:503狀態碼的存在并不意味著服務器在過載的時候必須使用它。某些服務器只不過是希望拒絕客戶端的連接。
504 Gateway Timeout
作為網關或者代理工作的服務器嘗試執行請求時,未能及時從上游服務器(URI標識出的服務器,例如HTTP、FTP、LDAP)或者輔助服務器(例如DNS)收到響應。
505 HTTP Version Not Supported
服務器不支持,或者拒絕支持在請求中使用的 HTTP 版本。這暗示著服務器不能或不愿使用與客戶端相同的版本。響應中應當包含一個描述了為何版本不被支持以及服務器支持哪些協議的實體。
感謝觀看!
參考資料:
https://www.runoob.com/http/http-status-codes.html
若想了解更多請參考:
HTTP狀態碼百度百科
https://blog.csdn.net/GarfieldEr007/article/details/77984065
HTML基礎知識
第一篇,HTML的結構
HTML中兩個概念
(1).HTML標簽:<元素名稱></元素名稱>
完整語法:<元素名稱>要控制的元素</元素名稱>
HTML標簽分為兩種: 成對:只對標簽內的元素起作用
單獨:在相應位置插入換行
標簽屬性設置在元素的首標簽:語法:<元素 屬性1=“值1” …>元素資料</元素>,""可省略
HTML元素: 一組標簽將一段文字包含在中間,這一組標簽與文字就是元素
結構
在所有的HTML文件中最外層由標簽建立,并包含兩個子標簽:元素為文件標題 :元素為文件主題
:說明文件標題和文件的一些公共屬性 :文件主體
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>HTML結構</title>
</head>
<body>
Hellow Word!
</body>
</html>
盒子模型與背景屬性
一.盒子模型
1.介紹
在Swift開發文檔中是這樣介紹閉包的:閉包是可以在你的代碼中被傳遞和引用的功能性獨立模塊。
Swift閉包
閉包的形式
Swift中的閉包有很多優化的地方
創建基本的閉包
在閉包中接收參數
從閉包中返回值
閉包作為參數
尾隨閉包語法
值捕獲
逃逸閉包
閉包的形式
全局函數 嵌套函數 閉包表達式
有名字但不能捕獲任何值。 有名字,也能捕獲封閉函數內的值。 無名閉包,使用輕量級語法,可以根據上下文環境捕獲值。
Swift中的閉包有很多優化的地方
根據上下文推斷參數和返回值類型
從單行表達式閉包中隱式返回(也就是閉包體只有一行代碼,可以省略return)
可以使用簡化參數名,如$0, $1(從0開始,表示第i個參數…)
提供了尾隨閉包語法(Trailing closure syntax)
閉包是引用類型:無論你將函數或閉包賦值給一個常量還是變量,你實際上都是將常量或變量的值設置為對應函數或閉包的引用
創建基本的閉包
let bibao = {
print("我要創建閉包")
}
上面的代碼實際上創建了一個匿名的函數,并將這個函數賦給了 driving。之后你就可以把 driving() 當作一個常規的函數來用,就像這樣:
bibao()
在閉包中接收參數
當你創建閉包的時候,它們并沒有名字,也沒有提供書寫參數的地方。但這并不意味著它們不能接收參數,只不過它們接收參數的方式稍有不同:這些參數是被寫在 花括號里面的。
為了讓一個閉包接收參數,你需要在花括號之后把這些參數列出來,然后跟上一個 in 關鍵字。這樣就告訴Swift,閉包的主體是從哪里開始的。
舉個例子,我們來創建一個閉包,接收一個叫 place 的字符串作為唯一的參數,就像這樣:
let bibao= { (bao1: String) in
print("我要創建 (bao1)。")
}
函數和閉包的一個區別是運行閉包的時候你不會用到參數標簽。因此,調用 driving() 的時候,我們是這樣寫的:
bibao("閉包")
從閉包中返回值
閉包也能返回值,寫法和閉包的參數類似:寫在閉包內部, in 關鍵字前面。
還是以 driving() 閉包為例, 讓它返回一個字符串。原來的函數是這樣的:
let bibao= { (bao1: String) in
print("我要創建 (bao1)。")
}
改成返回字符串而不是直接打印那個字符串,需要 in 之前添加 -> String,然后像常規函數那樣用到 return 關鍵字:
let drivingWithReturn = { (bao1: String) -> String in
return "我要創建 (bao1)。"
}
現在我們運行這個閉包并且打印出它的返回值:
let message = drivingWithReturn("閉包")
print(message)
閉包作為參數
既然閉包可以像字符串和整數一樣使用,你就可以將它們傳入函數。閉包作為參數的語法乍一看一看挺傷腦筋的,讓我們慢慢來。
首先,還是基本的 driving() 閉包。
let driving = {
print("我正在創建")
}
如果我們打算把這個閉包傳入一個函數,以便函數內部可以運行這個閉包。我們需要把函數的參數類型指定為 () -> Void。 它的意思是“不接收參數,并且返回 Void”。在Swift中,Void是什么也沒有的意思。
好了,讓我們來寫一個 travel() 函數,接收不同類型的 traveling 動作, 并且在動作前后分別打印信息:
func travel(action: () -> Void) {
print("我準備創建")
action()
print("我建好了")
}
現在可以用上 driving 閉包了,就像這樣:
travel(action: driving)
1
尾隨閉包語法
如果一個函數的最后一個參數是閉包,Swift允許你采用一種被稱為 “拖尾閉包語法” 的方式來調用這個閉包。你可以把閉包傳入函數之后的花括號里,而不必像傳入參數那樣。
又用到我們的 travel() 函數了。它接收一個 action 閉包。閉包在兩個 print() 調用之間執行:
func travel(action: () -> Void) {
print("我準備創建")
action()
print("我建好了")
}
由于函數的最后一個參數是閉包,我們可以用拖尾閉包語法來調用 travel() 函數,就像這樣:
travel() {
print("我要創建閉包")
}
實際上,由于函數沒有別的參數了,我們還可以將圓括號完全移除:
travel {
print("我要創建閉包")
}
拖尾閉包語法在Swift中非常常見,所以要加深印象。
值捕獲
閉包可以在其被定義的上下文中捕獲常量或變量。即使定義這些常量和變量的原作用域已經不存在,閉包仍然可以在閉包函數體內引用和修改這些值。
Swift 中,可以捕獲值的閉包的最簡單形式是嵌套函數,也就是定義在其他函數的函數體內的函數。嵌套函數可以捕獲其外部函數所有的參數以及定義的常量和變量。
官方文檔例子:
func makeIncrementer(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0
func incrementer() -> Int {
runningTotal += amount
return runningTotal
}
return incrementer
}
//運行結果:
let one = makeIncrementer(forIncrement: 10)
print(one()) //10
print(one()) //20
let two = makeIncrementer(forIncrement: 10)
print(two()) //10
print(two()) //20
逃逸閉包
當一個閉包作為參數傳到一個函數中,但是這個閉包在函數返回之后才被執行,我們稱該閉包從函數中逃逸。當你定義接受閉包作為參數的函數時,你可以在參數名之前標注 @escaping,用來指明這個閉包是允許“逃逸”出這個函數的。(默認值:@noescaping)
官方文檔例子:
var completionHandlers: [() -> Void] = []
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
completionHandlers.append(completionHandler)
}
如上面例子,加入標注@escaping即可表明這個閉包是允許逃逸的
以上就是我對Swift閉包的淺薄認知,如果有細節錯誤請指出,也可以查閱官方文檔,鏈接在下面教程更為詳細。
就是這樣啦,愛你們么么么~~
Vue中如何監控某個屬性值的變化?
比如現在需要監控data中,obj.a 的變化。Vue中監控對象屬性的變化你可以這樣:
watch: {
obj: {
handler (newValue, oldValue) {
console.log('obj changed')
},
deep: true
}
}
deep屬性表示深層遍歷,但是這么寫會監控obj的所有屬性變化,并不是我們想要的效果,所以做點修改:
watch: {
'obj.a': {
handler (newName, oldName) {
console.log('obj.a changed')
}
}
}
還有一種方法,可以通過computed 來實現,只需要:
computed: {
a1 () {
return this.obj.a
}
}
利用計算屬性的特性來實現,當依賴改變時,便會重新計算一個新值。
網上對于這兩個的區別解釋都是統一口徑的,一個是開發依賴,一個是線上依賴,打包發布需要用到的要添加到線上依賴,一模一樣的回答,誤導了很多人。今天自己測試一下這兩個命令,記錄一下。
–save-dev,會在devDependencies里面添加依賴
-D,會在devDependencies里面添加依賴
–save,會在dependencies里面添加依賴
-S,會在dependencies里面添加依賴
devDependencies和dependencies可以同時存在同一個包的依賴。
如果npm install xxx后面沒有輸入要保存到哪個里面,devDependencies和dependencies都沒有。
我這邊直接npm install jquery,node_modules下有jQuery。然后我刪除node_modules,執行npm install,node_modules下并沒有下載jQuery。
所以,安裝依賴的時候如果沒有加上要依賴到開發還是線上,只是臨時的在node_modules里面幫你下載,而devDependencies和dependencies的依賴都會幫你下載。
然后我在devDependencies下安裝依賴:
"devDependencies": {
"html-webpack-plugin": "^4.0.3",
"jquery": "^3.4.1",
"webpack": "^4.42.1",
"webpack-cli": "^3.3.11"
}
在入口文件引用和打印jQuery:
import $ from 'jquery'
console.log($)
打包之后,可以使用jQuery。
然后我在dependencies下安裝依賴:
"dependencies": {
"html-webpack-plugin": "^4.0.3",
"jquery": "^3.4.1",
"webpack": "^4.42.1",
"webpack-cli": "^3.3.11"
}
在入口文件引用和打印jQuery:
import $ from 'jquery'
console.log($)
打包之后,可以使用jQuery。
測試的結果就是,無論是–save還是–save-dev,對于打包都沒有任何影響。devDependencies和dependencies兩種情況,打包出來的main.js都把jQuery打包進去。這兩種情況,如果都沒有引用jQuery的情況下,也都不會把jQuery打包。
接著在一個空白的項目里面下載axios,npm install axios -S,打開node_modules文件夾:
發現多出了另外三個依賴,查看axios下的package.json:
"dependencies": {
"follow-redirects": "1.5.10"
}
查看follow-redirects下的package.json:
"dependencies": {
"debug": "=3.1.0"
}
查看debugs下的package.json:
"dependencies": {
"ms": "2.0.0"
}
最后ms的package.json沒有dependencies。
而這幾個包的devDependencies依賴的包沒有一個下載。
接著我在node_modules把follow-redirects、debugs、ms都刪了,把axios里面的package.js的dependencies給刪了,然后執行npm install,發現沒有下載follow-redirects、debugs、ms這幾個,也證明了如果node_modules里面有下載的包,是不會重新去下載的。我把node_modules刪除,執行npm install,這幾個包又都下載下來了。
最后得出 的結論是,–save-dev和–save在平時開發的時候,對于打包部署上線是沒有任何影響的。如果你是發布一個包給別人用,而你開發的包依賴第三方的包,那么你如果是–save,那么別人安裝你開發的包,會默認下載你依賴的包,如果你是–save-dev,那么別人安裝你開發的包,是不會默認幫忙下載你依賴的包。
其實發布的包如果沒有必要,很少會默認幫你下載,比如bootstrap,依賴jQuery,怕你原本就下載了引起沖突,也不會在dependencies里面安裝jQuery而是:
"peerDependencies": {
"jquery": "1.9.1 - 3",
"popper.js": "^1.16.0"
}
表示bootstrap依賴于這兩個包,你必須安裝,版本不固定,但是一定要安裝這兩個包,安裝的時候會有警告:
peerDependencies WARNING bootstrap@ requires a peer of jquery@1.9.1 - 3 but none was installed
peerDependencies WARNING bootstrap@ requires a peer of popper.js@^1.16.0 but none was installed
當你引用了然后打包,報錯:
ERROR in ./node_modules/_bootstrap@4.4.1@bootstrap/dist/js/bootstrap.js
Module not found: Error: Can't resolve 'jquery' in 'C:\Users\wade\Desktop\savedev\node_modules_bootstrap@4.4.1@bootstrap\dist\js'
@ ./node_modules/_bootstrap@4.4.1@bootstrap/dist/js/bootstrap.js 7:82-99
@ ./src/index.js
ERROR in ./node_modules/_bootstrap@4.4.1@bootstrap/dist/js/bootstrap.js
Module not found: Error: Can't resolve 'popper.js' in 'C:\Users\wade\Desktop\savedev\node_modules_bootstrap@4.4.1@bootstrap\dist\js'
@ ./node_modules/_bootstrap@4.4.1@bootstrap/dist/js/bootstrap.js 7:101-121
@ ./src/index.js
以上就是對–save和–save-dev的一些測試,想更快的得出結論其實是自己發布一個包。至于本人的答案是不是存在錯誤,歡迎指出,因為只是自己簡單測試的結果。
Node 的os模塊是操作系統的
Node 的內置模塊 fs
內置模塊在下載node的時候就自帶的,使用 require()方法來導入
語法 :require(‘模塊fs’)
在內置模塊中的方法
1 fs.readFile() —》用來專門 異步 讀取文件的方法 三個參數
語法 :fs.readFile(‘要讀取的文件’,讀取文件的格式,讀取成功的回調函數)
Eg : fs.readFIle(‘a’,’utf8’,’function(err,data){ })
2 fs.readFileSync()-– 專門用來 同步 讀取的方法, 兩個參數
語法: fs.readFileSync(‘要讀取的文件’,讀取格式)
3 fs.writeFIle() —>用來寫入 異步 文件的方法 三個參數
語法: fs.writeFile(‘寫入到哪個文件’,寫入的內容,成功的回調函數)
Eg: fs.writeFile(‘./text.tex’,”內容”, function(){ })
注意:再次寫入的內容會完全覆蓋 。如果文件夾沒有 會自動創建一個文件夾
4 fs.writeFileSync() --> 同步寫入的方法
語法: fs.writeFileSync(‘寫入到文件’,“寫入的內容”)
Node的http模塊
這個模塊專門用來創建服務的
只能支持http協議。
也是使用require()方法
Const http= require(“http”)
方法
1 http.createServer(function(req,res){ }) 兩個形參
Req=request 代表每次的請求信息
Res=response 代表每次請求的響應
返回值是一個服務,當服務監聽端口號的時候,就變成了服務器。
2 監聽端口號
創建的服務.listen(監聽的端口號,監聽成功的回調函數(選填))
server.listen(8080,function(){ 端口號0-65535 建議0-1023不使用 })
此時瀏覽器就可以執行localhost進行訪問了
自定義模塊
每一個js文件都是一個獨立的模塊,他們都自帶一個 module 是一個對象,
其中 module里面的 exports,是一個對象 這個 module.exports 就是這個文件向外導出的內容,也就是說,只有導出,才能導入
Eg: function fn1(){console.log() }
Module.exports.fn1=fn1
這樣,才能是另一個js文件到入這個文件 同樣也是require(‘./js’)方法
許多人都有這樣一種映像,NodeJS比較快; 但是因為其是單線程,所以它不穩定,有點不安全,不適合處理復雜業務; 它比較適合對并發要求比較高,而且簡單的業務場景。
在Express的作者的TJ Holowaychuk的 告別Node.js一文中列舉了以下罪狀:
Farewell NodeJS (TJ Holowaychuk)
? you may get duplicate callbacks
? you may not get a callback at all (lost in limbo)
? you may get out-of-band errors
? emitters may get multiple “error” events
? missing “error” events sends everything to hell
? often unsure what requires “error” handlers
? “error” handlers are very verbose
? callbacks suck
其實這幾條主要吐嘈了兩點: node.js錯誤處理很扯蛋,node.js的回調也很扯蛋。
事實上NodeJS里程確實有“脆弱”的一面,單線程的某處產生了“未處理的”異常確實會導致整個Node.JS的崩潰退出,來看個例子, 這里有一個node-error.js的文件:
var http = require('http'); var server = http.createServer(function (req, res) { //這里有個錯誤,params 是 undefined var ok = req.params.ok; res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('Hello World '); }); server.listen(8080, '127.0.0.1'); console.log('Server running at http://127.0.0.1:8080/');
啟動服務,并在地址欄測試一下發現 http://127.0.0.1:8080/ 不出所料,node崩潰了
$ node node-error Server running at http://127.0.0.1:8080/ c:githubscript ode-error.js:5 var ok = req.params.ok; ^ TypeError: Cannot read property 'ok' of undefined at Server.<anonymous> (c:githubscript ode-error.js:5:22) at Server.EventEmitter.emit (events.js:98:17) at HTTPParser.parser.onIncoming (http.js:2108:12) at HTTPParser.parserOnHeadersComplete [as onHeadersComplete] (http.js:121:23) at Socket.socket.ondata (http.js:1966:22) at TCP.onread (net.js:525:27)
其實Node.JS發展到今天,如果連這個問題都解決不了,那估計早就沒人用了。
我們可以uncaughtException來全局捕獲未捕獲的Error,同時你還可以將此函數的調用棧打印出來,捕獲之后可以有效防止node進程退出,如:
process.on('uncaughtException', function (err) { //打印出錯誤 console.log(err); //打印出錯誤的調用棧方便調試 console.log(err.stack); });
這相當于在node進程內部進行守護, 但這種方法很多人都是不提倡的,說明你還不能完全掌控Node.JS的異常。
我們還可以在回調前加try/catch,同樣確保線程的安全。
var http = require('http'); http.createServer(function(req, res) { try { handler(req, res); } catch(e) { console.log(' ', e, ' ', e.stack); try { res.end(e.stack); } catch(e) { } } }).listen(8080, '127.0.0.1'); console.log('Server running at http://127.0.0.1:8080/'); var handler = function (req, res) { //Error Popuped var name = req.params.name; res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('Hello ' + name); };
這種方案的好處是,可以將錯誤和調用棧直接輸出到當前發生的網頁上。
標準的HTTP響應處理會經歷一系列的Middleware(HttpModule),最終到達Handler,如下圖所示:
這 些Middleware和Handler在NodeJS中都有一個特點,他們都是回調函數,而回調函數中是唯一會讓Node在運行時崩潰的地方。根據這個 特點,我們只需要在框架中集成一處try/catch就可以相對完美地解決異常問題,而且不會影響其它用戶的請求request。
事實上現在的NodeJS WEB框架幾乎都是這么做的,如 OurJS開源博客所基于的 WebSvr
就有這么一處異常處理代碼:
Line: 207 try { handler(req, res); } catch(err) { var errorMsg = ' ' + 'Error ' + new Date().toISOString() + ' ' + req.url + ' ' + err.stack || err.message || 'unknow error' + ' ' ; console.error(errorMsg); Settings.showError ? res.end('<pre>' + errorMsg + '</pre>') : res.end(); }
那么不在回調中產生的錯誤怎么辦?不必擔心,其實這樣的node程序根本就起不起來。
此外node自帶的 cluster 也有一定的容錯能力,它跟nginx的worker很類似,但消耗資源(內存)略大,編程也不是很方便,OurJS并沒有采用此種設計。
現 在已經基本上解決了Node.JS因異常而崩潰的問題,不過任何平臺都不是100%可靠的,還有一些錯誤是從Node底層拋出的,有些異常 try/catch和uncaughtException都無法捕獲。之前在運行ourjs的時侯,會偶爾碰到底層拋出的文件流讀取異常,這就是一個底層 libuv的BUG,node.js在0.10.21中進行了修復。
面對這種情況,我們就應該為nodejs應用添加守護進程,讓NodeJS遭遇異常崩潰以后能馬上復活。
另外,還應該把這些產生的異常記錄到日志中,并讓異常永遠不再發生。
node-forever 提供了守護的功能和LOG日志記錄功能。
安裝非常容易
[sudo] npm install forever
使用也很簡單
$ forever start simple-server.js $ forever list [0] simple-server.js [ 24597, 24596 ]
還可以看日志
forever -o out.log -e err.log my-script.js
使用node來守護的話資源開銷可能會有點大,而且也會略顯復雜,OurJS直接在開機啟動腳本來進程線程守護。
如在debian中放置的 ourjs 開機啟動文件: /etc/init.d/ourjs
這個文件非常簡單,只有啟動的選項,守護的核心功能是由一個無限循環 while true; 來實現的,為了防止過于密集的錯誤阻塞進程,每次錯誤后間隔1秒重啟服務
WEB_DIR='/var/www/ourjs' WEB_APP='svr/ourjs.js' #location of node you want to use NODE_EXE=/root/local/bin/node while true; do { $NODE_EXE $WEB_DIR/$WEB_APP config.magazine.js echo "Stopped unexpected, restarting " } 2>> $WEB_DIR/error.log sleep 1 done
錯誤日志記錄也非常簡單,直接將此進程控制臺當中的錯誤輸出到error.log文件即可: 2>> $WEB_DIR/error.log 這一行, 2 代表 Error。
在一個asp.net 的項目中,前端通過ajax將富文本中的文字內容post到服務端的一個ashx中,在ashx中嘗試讀取參數值時,
結果報錯:“從客戶端中檢測到有潛在危險的 Request.Form 值”
#事故分析
由于在asp.net中,Request提交時出現有html代碼字符串時,程序系統會認為其具有潛在危險的值。會報出“從客戶端 中檢測到有潛在危險的Request.Form值”這樣的Error。
而富文本中的內容是包含html代碼的,所以...
#解決方案:
1、前端對富文本字符串進行encodeURI編碼,服務端進行HttpUtility.UrlDecode解碼操作;
前端代碼:
var str = '<p><span style="color: #00B0F0;"><em><strong>我想留在你的身邊,</strong></em></span><br/></p><p><span style="color: #7030A0;"><strong><span style="text-decoration: underline;">深情款款多么可憐;</span></strong></span></p>';
$(function() {
$.ajax({
type: "post",
url: "TestHandle.ashx",
data: { Title: 'jack', Content: encodeURI(str) },
success: function (data) {
$("#div").html(data);
}
});
});
后端代碼:
public void ProcessRequest(HttpContext context)
{
string str = context.Request["content"];
string content = HttpUtility.UrlDecode(str);
context.Response.ContentType = "text/plain";
context.Response.Write(content);
}
效果圖:
2、前端不以form的方式提交,直接以json方式提交,服務端從request的body中讀取數據,然后反序列化,得到信息;
前端代碼:
var str = '<p><span style="color: #00B0F0;"><em><strong>我想留在你的身邊,</strong></em></span><br/></p><p><span style="color: #7030A0;"><strong><span style="text-decoration: underline;">深情款款多么可憐;</span></strong></span></p>';
var temp = { Title: 'jack', Content: str };
$.ajax({
type: "post",
url: "TestHandle.ashx",
contentType:"application/json;charset=utf-8",
data: JSON.stringify(temp),
success: function (data) {
$("#div").html(data);
}
});
后端代碼:
string bodyText;
using (var bodyReader = new System.IO.StreamReader(context.Request.InputStream))
{
bodyText = bodyReader.ReadToEnd();
}
dynamic bodyObj = JsonConvert.DeserializeObject(bodyText);
context.Response.ContentType = "text/plain";
context.Response.Write(bodyObj.Content);
效果圖:
#其他場景的解決方案:
1、aspx頁面,當前頁面進行form提交
打開當前.aspx頁面,頁頭加上代碼:validateRequest=”false”,如:
<%@ Page Language="C#" ValidateRequest="false" AutoEventWireup="false" CodeFile="default.aspx.cs" Inherits="default" %>
該方法不推薦,還有一種修改web.config配置文件的方法,強烈不推薦,就不寫在這里了;
2、在ASP.NET MVC中的解決方案
1)、針對某個實體類的單個字段設置 [AllowHtml] ,這樣提交的時候,系統就會放過該字段。
2)、前端代碼:
var str = '<p><span style="color: #00B0F0;"><em><strong>我想留在你的身邊,</strong></em></span><br/></p><p><span style="color: #7030A0;"><strong><span style="text-decoration: underline;">深情款款多么可憐;</span></strong></span></p>';
$(function () {
$.ajax({
type: "post",
url: "Home/Test",
data: { Title: 'jack', Content: str },
success: function (data) {
$("#div").html(data.ok);
}
});
});
3)、后端代碼:
public class NewInfo
{
public string Title { get; set; }
[AllowHtml]
public string Content { get; set; }
}
#寫在最后
該文只是淺顯的總結一下,其中涉及的xss方面,沒有詳細考慮,歡迎指正!
藍藍設計的小編 http://www.syprn.cn