最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Nginx修改默認(rèn)錯(cuò)誤頁(yè)面的代碼詳解

 更新時(shí)間:2026年05月17日 15:22:31   作者:義龍道隱  
Nginx默認(rèn)的錯(cuò)誤頁(yè)面非常簡(jiǎn)單,只有一個(gè)純文本的提示,這對(duì)于用戶體驗(yàn)不夠友好,特別是在面向終端用戶的服務(wù)中,一個(gè)美觀的錯(cuò)誤頁(yè)面能夠大大提升產(chǎn)品的專業(yè)度,本文將介紹如何修改Nginx源碼,將默認(rèn)的錯(cuò)誤頁(yè)面替換為帶有CSS動(dòng)畫效果的自定義HTML頁(yè)面,需要的朋友可以參考下

一、背景

Nginx 默認(rèn)的錯(cuò)誤頁(yè)面非常簡(jiǎn)單,只有一個(gè)純文本的提示,如下圖。這對(duì)于用戶體驗(yàn)不夠友好,特別是在面向終端用戶的服務(wù)中,一個(gè)美觀的錯(cuò)誤頁(yè)面能夠大大提升產(chǎn)品的專業(yè)度。

本文將介紹如何修改 Nginx 源碼,將默認(rèn)的錯(cuò)誤頁(yè)面替換為帶有 CSS 動(dòng)畫效果的自定義 HTML 頁(yè)面。

二、Nginx 錯(cuò)誤頁(yè)面的存儲(chǔ)方式

Nginx 將錯(cuò)誤頁(yè)面以靜態(tài)字符串?dāng)?shù)組的形式定義在 src/http/ngx_http_special_response.c 文件中。每個(gè) HTTP 狀態(tài)碼對(duì)應(yīng)一個(gè)靜態(tài)字符數(shù)組:

static char ngx_http_error_404_page[] = 
    "<!DOCTYPE html>" CRLF
    "<html>" CRLF
    "<head><title>404 Not Found</title></head>" CRLF
    "<body>" CRLF
    "<center><h1>404 Not Found</h1></center>" CRLF
    "</body>" CRLF
    "</html>" CRLF;

三、需求分析

我們希望實(shí)現(xiàn)一個(gè)通用的錯(cuò)誤頁(yè)面模板,具有以下特點(diǎn):

  1. 美觀的 CSS 樣式:現(xiàn)代化的視覺(jué)效果,響應(yīng)式設(shè)計(jì)
  2. 數(shù)字動(dòng)畫效果:錯(cuò)誤碼的三個(gè)數(shù)字位分別帶有彈跳動(dòng)畫
  3. 易于維護(hù):使用宏定義避免重復(fù)代碼
  4. 編譯時(shí)確定:能夠靜態(tài)初始化,不影響運(yùn)行時(shí)性能

四、技術(shù)難點(diǎn)與解決方案

4.1 問(wèn)題:宏中不能進(jìn)行運(yùn)算

最初嘗試使用宏直接拆分?jǐn)?shù)字:

// ? 錯(cuò)誤示例
#define NGX_HTTP_ERROR_PAGE_TITLE(code, text) \
    "<div class=\"title\">" #code/100 "<span>" #code/10%10 "</span>" #code%10 "</div>"

問(wèn)題#code 會(huì)將參數(shù)字符串化,不能對(duì)其結(jié)果進(jìn)行運(yùn)算。

4.2 解決方案:手動(dòng)拆分?jǐn)?shù)字位

將數(shù)字的百位、十位、個(gè)位分別作為宏參數(shù)傳入:

#define NGX_HTTP_ERROR_PAGE_TITLE(code1, code2, code3, text) \
    "<div class=\"title\">" #code1 "<span>" #code2 "</span>" #code3 "</div>"

這樣每個(gè)數(shù)字位獨(dú)立使用 # 運(yùn)算符轉(zhuǎn)換為字符串,可以用于靜態(tài)數(shù)組初始化。

五、完整實(shí)現(xiàn)代碼

5.1 定義宏

需要增加一個(gè)宏定義,來(lái)實(shí)現(xiàn)錯(cuò)誤頁(yè)面通用模板,不用每個(gè) HTTP 狀態(tài)碼對(duì)應(yīng)的靜態(tài)字符數(shù)組都重復(fù)寫內(nèi)容。

5.2 錯(cuò)誤頁(yè)面模板宏

#define NGX_HTTP_ERROR_PAGE_TITLE(code1, code2, code3, text) \
    "<!DOCTYPE html>" CRLF \
    "<html lang=\"zh-CN\">" CRLF \
    "<head>" CRLF \
    "    <meta charset=\"UTF-8\">" CRLF \
    "    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">" CRLF \
    "    <title>" text "</title>" CRLF \
    "    <style>" CRLF \
    "        *{margin:0;padding:0;box-sizing:border-box;font-family:'Segoe UI','Microsoft YaHei',sans-serif}" CRLF \
    "        body{background:#fff;min-height:100vh;display:flex;justify-content:center;align-items:center;overflow:hidden}" CRLF \
    "        .error-container{text-align:center;padding:20px;max-width:700px;width:90%}" CRLF \
    "        .error-body{background:#fff;border-radius:10px;padding:60px 40px 40px;position:relative}" CRLF \
    "        .error-code{font-size:150px;font-weight:700;color:#2d8cf0;height:260px;line-height:260px;text-shadow:0 0 15px rgba(45,140,240,.6);margin-top:40px}" CRLF \
    "        .error-code span{display:inline-block;color:#19be6b;font-size:150px;animation:bounce 3s ease 0s infinite alternate;transform-origin:center}" CRLF \
    "        @keyframes bounce{0%{transform:rotateZ(0)}" CRLF \
    "        20%{transform:rotateZ(-60deg)}" CRLF \
    "        40%{transform:rotateZ(-10deg)}" CRLF \
    "        60%{transform:rotateZ(50deg)}" CRLF \
    "        80%{transform:rotateZ(-20deg)}" CRLF \
    "        100%{transform:rotateZ(0)}" CRLF \
    "        }" CRLF \
    "        .error-message{display:block;text-align:center;font-size:20px;font-weight:500;letter-spacing:5px;color:#dddde2}" CRLF \
    "        @media (max-width:768px){.error-code{font-size:120px;height:200px;line-height:200px}" CRLF \
    "        .error-code span{font-size:120px}" CRLF \
    "        }" CRLF \
    "        @media (max-width:480px){.error-code{font-size:90px;height:150px;line-height:150px}" CRLF \
    "        .error-code span{font-size:90px}" CRLF \
    "        .error-message{font-size:16px;letter-spacing:4px}" CRLF \
    "        }" CRLF \
    "    </style>" CRLF \
    "</head>" CRLF \
    "<body>" CRLF \
    "    <div class=\"error-container\">" CRLF \
    "        <div class=\"error-body\">" CRLF \
    "            <div class=\"error-code\">" #code1 "<span>" #code2 "</span>" #code3 "</div>" CRLF \
    "            <p class=\"error-message\">" text "</p>" CRLF \
    "        </div>" CRLF \
    "    </div>" CRLF \
    "</body>" CRLF \
    "</html>"

5.3 為各狀態(tài)碼生成錯(cuò)誤頁(yè)面

修改原來(lái)的各狀態(tài)碼錯(cuò)誤頁(yè)面定義部分,調(diào)用我們定義的宏:

/* 3xx 重定向錯(cuò)誤 */
static char ngx_http_error_301_page[] = NGX_HTTP_ERROR_PAGE_TITLE(3,0,1, "301 Moved Permanently");
static char ngx_http_error_302_page[] = NGX_HTTP_ERROR_PAGE_TITLE(3,0,2, "302 Found");
static char ngx_http_error_303_page[] = NGX_HTTP_ERROR_PAGE_TITLE(3,0,3, "303 See Other");
static char ngx_http_error_307_page[] = NGX_HTTP_ERROR_PAGE_TITLE(3,0,7, "307 Temporary Redirect");
static char ngx_http_error_308_page[] = NGX_HTTP_ERROR_PAGE_TITLE(3,0,8, "308 Permanent Redirect");

/* 4xx 客戶端錯(cuò)誤 */
static char ngx_http_error_400_page[] = NGX_HTTP_ERROR_PAGE_TITLE(4,0,0, "400 Bad Request");
static char ngx_http_error_401_page[] = NGX_HTTP_ERROR_PAGE_TITLE(4,0,1, "401 Authorization Required");
static char ngx_http_error_403_page[] = NGX_HTTP_ERROR_PAGE_TITLE(4,0,3, "403 Forbidden");
static char ngx_http_error_404_page[] = NGX_HTTP_ERROR_PAGE_TITLE(4,0,4, "404 Not Found");
static char ngx_http_error_405_page[] = NGX_HTTP_ERROR_PAGE_TITLE(4,0,5, "405 Not Allowed");
static char ngx_http_error_406_page[] = NGX_HTTP_ERROR_PAGE_TITLE(4,0,6, "406 Not Acceptable");
static char ngx_http_error_407_page[] = NGX_HTTP_ERROR_PAGE_TITLE(4,0,7, "407 Proxy Authentication Required");
static char ngx_http_error_408_page[] = NGX_HTTP_ERROR_PAGE_TITLE(4,0,8, "408 Request Time-out");
static char ngx_http_error_409_page[] = NGX_HTTP_ERROR_PAGE_TITLE(4,0,9, "409 Conflict");
static char ngx_http_error_410_page[] = NGX_HTTP_ERROR_PAGE_TITLE(4,1,0, "410 Gone");
static char ngx_http_error_411_page[] = NGX_HTTP_ERROR_PAGE_TITLE(4,1,1, "411 Length Required");
static char ngx_http_error_412_page[] = NGX_HTTP_ERROR_PAGE_TITLE(4,1,2, "412 Precondition Failed");
static char ngx_http_error_413_page[] = NGX_HTTP_ERROR_PAGE_TITLE(4,1,3, "413 Request Entity Too Large");
static char ngx_http_error_414_page[] = NGX_HTTP_ERROR_PAGE_TITLE(4,1,4, "414 Request-URI Too Large");
static char ngx_http_error_415_page[] = NGX_HTTP_ERROR_PAGE_TITLE(4,1,5, "415 Unsupported Media Type");
static char ngx_http_error_416_page[] = NGX_HTTP_ERROR_PAGE_TITLE(4,1,6, "416 Requested Range Not Satisfiable");
static char ngx_http_error_421_page[] = NGX_HTTP_ERROR_PAGE_TITLE(4,2,1, "421 Misdirected Request");
static char ngx_http_error_429_page[] = NGX_HTTP_ERROR_PAGE_TITLE(4,2,9, "429 Too Many Requests");
static char ngx_http_error_494_page[] = NGX_HTTP_ERROR_PAGE_TITLE(4,9,4, "400 Request Header Or Cookie Too Large");
static char ngx_http_error_495_page[] = NGX_HTTP_ERROR_PAGE_TITLE(4,9,5, "400 The SSL certificate error");
static char ngx_http_error_496_page[] = NGX_HTTP_ERROR_PAGE_TITLE(4,9,6, "400 No required SSL certificate was sent");
static char ngx_http_error_497_page[] = NGX_HTTP_ERROR_PAGE_TITLE(4,9,7, "400 The plain HTTP request was sent to HTTPS port");

/* 5xx 服務(wù)端錯(cuò)誤 */
static char ngx_http_error_500_page[] = NGX_HTTP_ERROR_PAGE_TITLE(5,0,0, "500 Internal Server Error");
static char ngx_http_error_501_page[] = NGX_HTTP_ERROR_PAGE_TITLE(5,0,1, "501 Not Implemented");
static char ngx_http_error_502_page[] = NGX_HTTP_ERROR_PAGE_TITLE(5,0,2, "502 Bad Gateway");
static char ngx_http_error_503_page[] = NGX_HTTP_ERROR_PAGE_TITLE(5,0,3, "503 Service Temporarily Unavailable");
static char ngx_http_error_504_page[] = NGX_HTTP_ERROR_PAGE_TITLE(5,0,4, "504 Gateway Time-out");
static char ngx_http_error_505_page[] = NGX_HTTP_ERROR_PAGE_TITLE(5,0,5, "505 HTTP Version Not Supported");
static char ngx_http_error_507_page[] = NGX_HTTP_ERROR_PAGE_TITLE(5,0,7, "507 Insufficient Storage");

5.4 修改后的完整代碼

修改后的完整ngx_http_special_response.c代碼,只做增強(qiáng),沒(méi)有改變?cè)瓉?lái)架構(gòu)邏輯:

/*
 * Copyright (C) Igor Sysoev
 * Copyright (C) Nginx, Inc.
 */


#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
#include <nginx.h>


static ngx_int_t ngx_http_send_error_page(ngx_http_request_t *r,
    ngx_http_err_page_t *err_page);
static ngx_int_t ngx_http_send_special_response(ngx_http_request_t *r,
    ngx_http_core_loc_conf_t *clcf, ngx_uint_t err);
static ngx_int_t ngx_http_send_refresh(ngx_http_request_t *r);


static u_char ngx_http_error_full_tail[] =
"" CRLF
;


static u_char ngx_http_error_build_tail[] =
"" CRLF
;


static u_char ngx_http_error_tail[] =
"" CRLF
;


static u_char ngx_http_msie_padding[] =
"<!-- a padding to disable MSIE and Chrome friendly error page -->" CRLF
"<!-- a padding to disable MSIE and Chrome friendly error page -->" CRLF
"<!-- a padding to disable MSIE and Chrome friendly error page -->" CRLF
"<!-- a padding to disable MSIE and Chrome friendly error page -->" CRLF
"<!-- a padding to disable MSIE and Chrome friendly error page -->" CRLF
"<!-- a padding to disable MSIE and Chrome friendly error page -->" CRLF
;


static u_char ngx_http_msie_refresh_head[] =
"<html><head><meta http-equiv=\"Refresh\" content=\"0; URL=";


static u_char ngx_http_msie_refresh_tail[] =
"\"></head><body></body></html>" CRLF;

/* 定義模板宏 通用錯(cuò)誤頁(yè)面模板 */
#define NGX_HTTP_ERROR_PAGE_TITLE(code1,code2,code3, text) \
    "<!DOCTYPE html>" CRLF \
    "<html lang=\"zh-CN\">" CRLF \
    "<head>" CRLF \
    "    <meta charset=\"UTF-8\">" CRLF \
    "    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">" CRLF \
    "    <title>" text "</title>" CRLF \
    "    <style>" CRLF \
    "        *{margin:0;padding:0;box-sizing:border-box;font-family:'Segoe UI','Microsoft YaHei',sans-serif}" CRLF \
    "        body{background:#fff;min-height:100vh;display:flex;justify-content:center;align-items:center;overflow:hidden}" CRLF \
    "        .error404{text-align:center;padding:20px;max-width:700px;width:90%}" CRLF \
    "        .error404-body-con{background:#fff;border-radius:10px;padding:60px 40px 40px;position:relative}" CRLF \
    "        .error404-body-con-title{font-size:150px;font-weight:700;color:#2d8cf0;height:260px;line-height:260px;text-shadow:0 0 15px rgba(45,140,240,.6);margin-top:40px}" CRLF \
    "        .error404-body-con-title span{display:inline-block;color:#19be6b;font-size:150px;animation:error404animation 3s ease 0s infinite alternate;transform-origin:center}" CRLF \
    "        @keyframes error404animation{0%{transform:rotateZ(0)}" CRLF \
    "        20%{transform:rotateZ(-60deg)}" CRLF \
    "        40%{transform:rotateZ(-10deg)}" CRLF \
    "        60%{transform:rotateZ(50deg)}" CRLF \
    "        80%{transform:rotateZ(-20deg)}" CRLF \
    "        100%{transform:rotateZ(0)}" CRLF \
    "        }" CRLF \
    "        .error404-body-con-message{display:block;text-align:center;font-size:20px;font-weight:500;letter-spacing:5px;color:#dddde2}" CRLF \
    "        @media (max-width:768px){.error404-body-con-title{font-size:120px;height:200px;line-height:200px}" CRLF \
    "        .error404-body-con-title span{font-size:120px}" CRLF \
    "        }" CRLF \
    "        @media (max-width:480px){.error404-body-con-title{font-size:90px;height:150px;line-height:150px}" CRLF \
    "        .error404-body-con-title span{font-size:90px}" CRLF \
    "        .error404-body-con-message{font-size:16px;letter-spacing:4px}" CRLF \
    "        }" CRLF \
    "    </style>" CRLF \
    "</head>" CRLF \
    "<body>" CRLF \
    "    <div class=\"error404\">" CRLF \
    "        <div class=\"error404-body-con\">" CRLF \
    "            <div class=\"error404-body-con-title\">" #code1 "<span>" #code2 "</span>" #code3 "</div>" CRLF \
    "            <p class=\"error404-body-con-message\">" text "</p>" CRLF \
    "        </div>" CRLF \
    "    </div>" CRLF \
    "</body>" CRLF \
    "</html>"


/* 為每個(gè)狀態(tài)碼生成頁(yè)面 */
static char ngx_http_error_301_page[] = NGX_HTTP_ERROR_PAGE_TITLE(3,0,1, "301 Moved Permanently");
static char ngx_http_error_302_page[] = NGX_HTTP_ERROR_PAGE_TITLE(3,0,2, "302 Found");
static char ngx_http_error_303_page[] = NGX_HTTP_ERROR_PAGE_TITLE(3,0,3, "303 See Other");
static char ngx_http_error_307_page[] = NGX_HTTP_ERROR_PAGE_TITLE(3,0,7, "307 Temporary Redirect");
static char ngx_http_error_308_page[] = NGX_HTTP_ERROR_PAGE_TITLE(3,0,8, "308 Permanent Redirect");
static char ngx_http_error_400_page[] = NGX_HTTP_ERROR_PAGE_TITLE(4,0,0, "400 Bad Request");
static char ngx_http_error_401_page[] = NGX_HTTP_ERROR_PAGE_TITLE(4,0,1, "401 Authorization Required");
static char ngx_http_error_402_page[] = NGX_HTTP_ERROR_PAGE_TITLE(4,0,2, "402 Payment Required");
static char ngx_http_error_403_page[] = NGX_HTTP_ERROR_PAGE_TITLE(4,0,3, "403 Forbidden");
static char ngx_http_error_404_page[] = NGX_HTTP_ERROR_PAGE_TITLE(4,0,4, "404 Not Found");
static char ngx_http_error_405_page[] = NGX_HTTP_ERROR_PAGE_TITLE(4,0,5, "405 Not Allowed");
static char ngx_http_error_406_page[] = NGX_HTTP_ERROR_PAGE_TITLE(4,0,6, "406 Not Acceptable");
static char ngx_http_error_407_page[] = NGX_HTTP_ERROR_PAGE_TITLE(4,0,7, "407 Proxy Authentication Required");
static char ngx_http_error_408_page[] = NGX_HTTP_ERROR_PAGE_TITLE(4,0,8, "408 Request Time-out");
static char ngx_http_error_409_page[] = NGX_HTTP_ERROR_PAGE_TITLE(4,0,9, "409 Conflict");
static char ngx_http_error_410_page[] = NGX_HTTP_ERROR_PAGE_TITLE(4,1,0, "410 Gone");
static char ngx_http_error_411_page[] = NGX_HTTP_ERROR_PAGE_TITLE(4,1,1, "411 Length Required");
static char ngx_http_error_412_page[] = NGX_HTTP_ERROR_PAGE_TITLE(4,1,2, "412 Precondition Failed");
static char ngx_http_error_413_page[] = NGX_HTTP_ERROR_PAGE_TITLE(4,1,3, "413 Request Entity Too Large");
static char ngx_http_error_414_page[] = NGX_HTTP_ERROR_PAGE_TITLE(4,1,4, "414 Request-URI Too Large");
static char ngx_http_error_415_page[] = NGX_HTTP_ERROR_PAGE_TITLE(4,1,5, "415 Unsupported Media Type");
static char ngx_http_error_416_page[] = NGX_HTTP_ERROR_PAGE_TITLE(4,1,6, "416 Requested Range Not Satisfiable");
static char ngx_http_error_421_page[] = NGX_HTTP_ERROR_PAGE_TITLE(4,2,1, "421 Misdirected Request");
static char ngx_http_error_429_page[] = NGX_HTTP_ERROR_PAGE_TITLE(4,2,9, "429 Too Many Requests");
static char ngx_http_error_494_page[] = NGX_HTTP_ERROR_PAGE_TITLE(4,9,4, "400 Request Header Or Cookie Too Large");
static char ngx_http_error_495_page[] = NGX_HTTP_ERROR_PAGE_TITLE(4,9,5, "400 The SSL certificate error");
static char ngx_http_error_496_page[] = NGX_HTTP_ERROR_PAGE_TITLE(4,9,6, "400 No required SSL certificate was sent");
static char ngx_http_error_497_page[] = NGX_HTTP_ERROR_PAGE_TITLE(4,9,7, "400 The plain HTTP request was sent to HTTPS port");
static char ngx_http_error_500_page[] = NGX_HTTP_ERROR_PAGE_TITLE(5,0,0, "500 Internal Server Error");
static char ngx_http_error_501_page[] = NGX_HTTP_ERROR_PAGE_TITLE(5,0,1, "501 Not Implemented");
static char ngx_http_error_502_page[] = NGX_HTTP_ERROR_PAGE_TITLE(5,0,2, "502 Bad Gateway");
static char ngx_http_error_503_page[] = NGX_HTTP_ERROR_PAGE_TITLE(5,0,3, "503 Service Temporarily Unavailable");
static char ngx_http_error_504_page[] = NGX_HTTP_ERROR_PAGE_TITLE(5,0,4, "504 Gateway Time-out");
static char ngx_http_error_505_page[] = NGX_HTTP_ERROR_PAGE_TITLE(5,0,5, "505 HTTP Version Not Supported");
static char ngx_http_error_507_page[] = NGX_HTTP_ERROR_PAGE_TITLE(5,0,7, "507 Insufficient Storage");


static ngx_str_t ngx_http_error_pages[] = {

    ngx_null_string,                     /* 201, 204 */

#define NGX_HTTP_LAST_2XX  202
#define NGX_HTTP_OFF_3XX   (NGX_HTTP_LAST_2XX - 201)

    /* ngx_null_string, */               /* 300 */
    ngx_string(ngx_http_error_301_page),
    ngx_string(ngx_http_error_302_page),
    ngx_string(ngx_http_error_303_page),
    ngx_null_string,                     /* 304 */
    ngx_null_string,                     /* 305 */
    ngx_null_string,                     /* 306 */
    ngx_string(ngx_http_error_307_page),
    ngx_string(ngx_http_error_308_page),

#define NGX_HTTP_LAST_3XX  309
#define NGX_HTTP_OFF_4XX   (NGX_HTTP_LAST_3XX - 301 + NGX_HTTP_OFF_3XX)

    ngx_string(ngx_http_error_400_page),
    ngx_string(ngx_http_error_401_page),
    ngx_string(ngx_http_error_402_page),
    ngx_string(ngx_http_error_403_page),
    ngx_string(ngx_http_error_404_page),
    ngx_string(ngx_http_error_405_page),
    ngx_string(ngx_http_error_406_page),
    ngx_string(ngx_http_error_407_page),
    ngx_string(ngx_http_error_408_page),
    ngx_string(ngx_http_error_409_page),
    ngx_string(ngx_http_error_410_page),
    ngx_string(ngx_http_error_411_page),
    ngx_string(ngx_http_error_412_page),
    ngx_string(ngx_http_error_413_page),
    ngx_string(ngx_http_error_414_page),
    ngx_string(ngx_http_error_415_page),
    ngx_string(ngx_http_error_416_page),
    ngx_null_string,                     /* 417 */
    ngx_null_string,                     /* 418 */
    ngx_null_string,                     /* 419 */
    ngx_null_string,                     /* 420 */
    ngx_string(ngx_http_error_421_page),
    ngx_null_string,                     /* 422 */
    ngx_null_string,                     /* 423 */
    ngx_null_string,                     /* 424 */
    ngx_null_string,                     /* 425 */
    ngx_null_string,                     /* 426 */
    ngx_null_string,                     /* 427 */
    ngx_null_string,                     /* 428 */
    ngx_string(ngx_http_error_429_page),

#define NGX_HTTP_LAST_4XX  430
#define NGX_HTTP_OFF_5XX   (NGX_HTTP_LAST_4XX - 400 + NGX_HTTP_OFF_4XX)

    ngx_string(ngx_http_error_494_page), /* 494, request header too large */
    ngx_string(ngx_http_error_495_page), /* 495, https certificate error */
    ngx_string(ngx_http_error_496_page), /* 496, https no certificate */
    ngx_string(ngx_http_error_497_page), /* 497, http to https */
    ngx_string(ngx_http_error_404_page), /* 498, canceled */
    ngx_null_string,                     /* 499, client has closed connection */

    ngx_string(ngx_http_error_500_page),
    ngx_string(ngx_http_error_501_page),
    ngx_string(ngx_http_error_502_page),
    ngx_string(ngx_http_error_503_page),
    ngx_string(ngx_http_error_504_page),
    ngx_string(ngx_http_error_505_page),
    ngx_null_string,                     /* 506 */
    ngx_string(ngx_http_error_507_page)

#define NGX_HTTP_LAST_5XX  508

};


ngx_int_t
ngx_http_special_response_handler(ngx_http_request_t *r, ngx_int_t error)
{
    ngx_uint_t                 i, err;
    ngx_http_err_page_t       *err_page;
    ngx_http_core_loc_conf_t  *clcf;

    ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "http special response: %i, \"%V?%V\"",
                   error, &r->uri, &r->args);

    r->err_status = error;

    if (r->keepalive) {
        switch (error) {
            case NGX_HTTP_BAD_REQUEST:
            case NGX_HTTP_REQUEST_ENTITY_TOO_LARGE:
            case NGX_HTTP_REQUEST_URI_TOO_LARGE:
            case NGX_HTTP_TO_HTTPS:
            case NGX_HTTPS_CERT_ERROR:
            case NGX_HTTPS_NO_CERT:
            case NGX_HTTP_INTERNAL_SERVER_ERROR:
            case NGX_HTTP_NOT_IMPLEMENTED:
                r->keepalive = 0;
        }
    }

    if (r->lingering_close) {
        switch (error) {
            case NGX_HTTP_BAD_REQUEST:
            case NGX_HTTP_TO_HTTPS:
            case NGX_HTTPS_CERT_ERROR:
            case NGX_HTTPS_NO_CERT:
                r->lingering_close = 0;
        }
    }

    r->headers_out.content_type.len = 0;

    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

    if (!r->error_page && clcf->error_pages && r->uri_changes != 0) {

        if (clcf->recursive_error_pages == 0) {
            r->error_page = 1;
        }

        err_page = clcf->error_pages->elts;

        for (i = 0; i < clcf->error_pages->nelts; i++) {
            if (err_page[i].status == error) {
                return ngx_http_send_error_page(r, &err_page[i]);
            }
        }
    }

    r->expect_tested = 1;

    if (ngx_http_discard_request_body(r) != NGX_OK) {
        r->keepalive = 0;
    }

    if (clcf->msie_refresh
        && r->headers_in.msie
        && (error == NGX_HTTP_MOVED_PERMANENTLY
            || error == NGX_HTTP_MOVED_TEMPORARILY))
    {
        return ngx_http_send_refresh(r);
    }

    if (error == NGX_HTTP_CREATED) {
        /* 201 */
        err = 0;

    } else if (error == NGX_HTTP_NO_CONTENT) {
        /* 204 */
        err = 0;

    } else if (error >= NGX_HTTP_MOVED_PERMANENTLY
               && error < NGX_HTTP_LAST_3XX)
    {
        /* 3XX */
        err = error - NGX_HTTP_MOVED_PERMANENTLY + NGX_HTTP_OFF_3XX;

    } else if (error >= NGX_HTTP_BAD_REQUEST
               && error < NGX_HTTP_LAST_4XX)
    {
        /* 4XX */
        err = error - NGX_HTTP_BAD_REQUEST + NGX_HTTP_OFF_4XX;

    } else if (error >= NGX_HTTP_NGINX_CODES
               && error < NGX_HTTP_LAST_5XX)
    {
        /* 49X, 5XX */
        err = error - NGX_HTTP_NGINX_CODES + NGX_HTTP_OFF_5XX;
        switch (error) {
            case NGX_HTTP_TO_HTTPS:
            case NGX_HTTPS_CERT_ERROR:
            case NGX_HTTPS_NO_CERT:
            case NGX_HTTP_REQUEST_HEADER_TOO_LARGE:
                r->err_status = NGX_HTTP_BAD_REQUEST;
        }

    } else {
        /* unknown code, zero body */
        err = 0;
    }

    return ngx_http_send_special_response(r, clcf, err);
}


ngx_int_t
ngx_http_filter_finalize_request(ngx_http_request_t *r, ngx_module_t *m,
    ngx_int_t error)
{
    void       *ctx;
    ngx_int_t   rc;

    ngx_http_clean_header(r);

    ctx = NULL;

    if (m) {
        ctx = r->ctx[m->ctx_index];
    }

    /* clear the modules contexts */
    ngx_memzero(r->ctx, sizeof(void *) * ngx_http_max_module);

    if (m) {
        r->ctx[m->ctx_index] = ctx;
    }

    r->filter_finalize = 1;

    rc = ngx_http_special_response_handler(r, error);

    /* NGX_ERROR resets any pending data */

    switch (rc) {

    case NGX_OK:
    case NGX_DONE:
        return NGX_ERROR;

    default:
        return rc;
    }
}


void
ngx_http_clean_header(ngx_http_request_t *r)
{
    ngx_memzero(&r->headers_out.status,
                sizeof(ngx_http_headers_out_t)
                    - offsetof(ngx_http_headers_out_t, status));

    r->headers_out.headers.part.nelts = 0;
    r->headers_out.headers.part.next = NULL;
    r->headers_out.headers.last = &r->headers_out.headers.part;

    r->headers_out.trailers.part.nelts = 0;
    r->headers_out.trailers.part.next = NULL;
    r->headers_out.trailers.last = &r->headers_out.trailers.part;

    r->headers_out.content_length_n = -1;
    r->headers_out.last_modified_time = -1;
}


static ngx_int_t
ngx_http_send_error_page(ngx_http_request_t *r, ngx_http_err_page_t *err_page)
{
    ngx_int_t                  overwrite;
    ngx_str_t                  uri, args;
    ngx_table_elt_t           *location;
    ngx_http_core_loc_conf_t  *clcf;

    overwrite = err_page->overwrite;

    if (overwrite && overwrite != NGX_HTTP_OK) {
        r->expect_tested = 1;
    }

    if (overwrite >= 0) {
        r->err_status = overwrite;
    }

    if (ngx_http_complex_value(r, &err_page->value, &uri) != NGX_OK) {
        return NGX_ERROR;
    }

    if (uri.len && uri.data[0] == '/') {

        if (err_page->value.lengths) {
            ngx_http_split_args(r, &uri, &args);

        } else {
            args = err_page->args;
        }

        if (r->method != NGX_HTTP_HEAD) {
            r->method = NGX_HTTP_GET;
            r->method_name = ngx_http_core_get_method;
        }

        return ngx_http_internal_redirect(r, &uri, &args);
    }

    if (uri.len && uri.data[0] == '@') {
        return ngx_http_named_location(r, &uri);
    }

    r->expect_tested = 1;

    if (ngx_http_discard_request_body(r) != NGX_OK) {
        r->keepalive = 0;
    }

    location = ngx_list_push(&r->headers_out.headers);

    if (location == NULL) {
        return NGX_ERROR;
    }

    if (overwrite != NGX_HTTP_MOVED_PERMANENTLY
        && overwrite != NGX_HTTP_MOVED_TEMPORARILY
        && overwrite != NGX_HTTP_SEE_OTHER
        && overwrite != NGX_HTTP_TEMPORARY_REDIRECT
        && overwrite != NGX_HTTP_PERMANENT_REDIRECT)
    {
        r->err_status = NGX_HTTP_MOVED_TEMPORARILY;
    }

    location->hash = 1;
    location->next = NULL;
    ngx_str_set(&location->key, "Location");
    location->value = uri;

    ngx_http_clear_location(r);

    r->headers_out.location = location;

    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

    if (clcf->msie_refresh && r->headers_in.msie) {
        return ngx_http_send_refresh(r);
    }

    return ngx_http_send_special_response(r, clcf, r->err_status
                                                   - NGX_HTTP_MOVED_PERMANENTLY
                                                   + NGX_HTTP_OFF_3XX);
}


static ngx_int_t
ngx_http_send_special_response(ngx_http_request_t *r,
    ngx_http_core_loc_conf_t *clcf, ngx_uint_t err)
{
    u_char       *tail;
    size_t        len;
    ngx_int_t     rc;
    ngx_buf_t    *b;
    ngx_uint_t    msie_padding;
    ngx_chain_t   out[3];

    if (clcf->server_tokens == NGX_HTTP_SERVER_TOKENS_ON) {
        len = sizeof(ngx_http_error_full_tail) - 1;
        tail = ngx_http_error_full_tail;

    } else if (clcf->server_tokens == NGX_HTTP_SERVER_TOKENS_BUILD) {
        len = sizeof(ngx_http_error_build_tail) - 1;
        tail = ngx_http_error_build_tail;

    } else {
        len = sizeof(ngx_http_error_tail) - 1;
        tail = ngx_http_error_tail;
    }

    msie_padding = 0;

    if (ngx_http_error_pages[err].len) {
        r->headers_out.content_length_n = ngx_http_error_pages[err].len + len;
        if (clcf->msie_padding
            && (r->headers_in.msie || r->headers_in.chrome)
            && r->http_version >= NGX_HTTP_VERSION_10
            && err >= NGX_HTTP_OFF_4XX)
        {
            r->headers_out.content_length_n +=
                                         sizeof(ngx_http_msie_padding) - 1;
            msie_padding = 1;
        }

        r->headers_out.content_type_len = sizeof("text/html") - 1;
        ngx_str_set(&r->headers_out.content_type, "text/html");
        r->headers_out.content_type_lowcase = NULL;

    } else {
        r->headers_out.content_length_n = 0;
    }

    if (r->headers_out.content_length) {
        r->headers_out.content_length->hash = 0;
        r->headers_out.content_length = NULL;
    }

    ngx_http_clear_accept_ranges(r);
    ngx_http_clear_last_modified(r);
    ngx_http_clear_etag(r);

    rc = ngx_http_send_header(r);

    if (rc == NGX_ERROR || r->header_only) {
        return rc;
    }

    if (ngx_http_error_pages[err].len == 0) {
        return ngx_http_send_special(r, NGX_HTTP_LAST);
    }

    b = ngx_calloc_buf(r->pool);
    if (b == NULL) {
        return NGX_ERROR;
    }

    b->memory = 1;
    b->pos = ngx_http_error_pages[err].data;
    b->last = ngx_http_error_pages[err].data + ngx_http_error_pages[err].len;

    out[0].buf = b;
    out[0].next = &out[1];

    b = ngx_calloc_buf(r->pool);
    if (b == NULL) {
        return NGX_ERROR;
    }

    b->memory = 1;

    b->pos = tail;
    b->last = tail + len;

    out[1].buf = b;
    out[1].next = NULL;

    if (msie_padding) {
        b = ngx_calloc_buf(r->pool);
        if (b == NULL) {
            return NGX_ERROR;
        }

        b->memory = 1;
        b->pos = ngx_http_msie_padding;
        b->last = ngx_http_msie_padding + sizeof(ngx_http_msie_padding) - 1;

        out[1].next = &out[2];
        out[2].buf = b;
        out[2].next = NULL;
    }

    if (r == r->main) {
        b->last_buf = 1;
    }

    b->last_in_chain = 1;

    return ngx_http_output_filter(r, &out[0]);
}


static ngx_int_t
ngx_http_send_refresh(ngx_http_request_t *r)
{
    u_char       *p, *location;
    size_t        len, size;
    uintptr_t     escape;
    ngx_int_t     rc;
    ngx_buf_t    *b;
    ngx_chain_t   out;

    len = r->headers_out.location->value.len;
    location = r->headers_out.location->value.data;

    escape = 2 * ngx_escape_uri(NULL, location, len, NGX_ESCAPE_REFRESH);

    size = sizeof(ngx_http_msie_refresh_head) - 1
           + escape + len
           + sizeof(ngx_http_msie_refresh_tail) - 1;

    r->err_status = NGX_HTTP_OK;

    r->headers_out.content_type_len = sizeof("text/html") - 1;
    ngx_str_set(&r->headers_out.content_type, "text/html");
    r->headers_out.content_type_lowcase = NULL;

    r->headers_out.location->hash = 0;
    r->headers_out.location = NULL;

    r->headers_out.content_length_n = size;

    if (r->headers_out.content_length) {
        r->headers_out.content_length->hash = 0;
        r->headers_out.content_length = NULL;
    }

    ngx_http_clear_accept_ranges(r);
    ngx_http_clear_last_modified(r);
    ngx_http_clear_etag(r);

    rc = ngx_http_send_header(r);

    if (rc == NGX_ERROR || r->header_only) {
        return rc;
    }

    b = ngx_create_temp_buf(r->pool, size);
    if (b == NULL) {
        return NGX_ERROR;
    }

    p = ngx_cpymem(b->pos, ngx_http_msie_refresh_head,
                   sizeof(ngx_http_msie_refresh_head) - 1);

    if (escape == 0) {
        p = ngx_cpymem(p, location, len);

    } else {
        p = (u_char *) ngx_escape_uri(p, location, len, NGX_ESCAPE_REFRESH);
    }

    b->last = ngx_cpymem(p, ngx_http_msie_refresh_tail,
                         sizeof(ngx_http_msie_refresh_tail) - 1);

    b->last_buf = (r == r->main) ? 1 : 0;
    b->last_in_chain = 1;

    out.buf = b;
    out.next = NULL;

    return ngx_http_output_filter(r, &out);
}

六、實(shí)現(xiàn)效果

修改完成后,重新編譯 Nginx:

./configure --prefix=/usr/local/nginx \
--conf-path=/usr/local/nginx/etc/nginx.conf \
--sbin-path=/usr/local/nginx/sbin/nginx \
--user=nginx \
--group=nginx \
--with-pcre \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_v3_module \
--with-http_realip_module \
--with-http_addition_module \
--with-http_image_filter_module \
--with-http_sub_module \
--with-http_dav_module \
--with-http_flv_module \
--with-http_mp4_module \
--with-http_gzip_static_module \
--with-http_random_index_module \
--with-http_secure_link_module \
--with-http_degradation_module \
--with-http_stub_status_module \
--with-stream \
--with-mail

make
make install

訪問(wèn)一個(gè)不存在的頁(yè)面,你將看到帶有 CSS 動(dòng)畫效果的自定義錯(cuò)誤頁(yè)面(效果如下圖):

  • 錯(cuò)誤碼的每個(gè)數(shù)字位獨(dú)立顯示
  • 中間的數(shù)字(十位)帶有旋轉(zhuǎn)彈跳動(dòng)畫
  • 響應(yīng)式設(shè)計(jì),在移動(dòng)端自動(dòng)調(diào)整字體大小
  • 現(xiàn)代化的視覺(jué)風(fēng)格,帶陰影和圓角

七、技術(shù)要點(diǎn)總結(jié)

  1. 宏的參數(shù)化設(shè)計(jì):通過(guò)將復(fù)雜邏輯拆分為多個(gè)參數(shù),避開(kāi)了宏的運(yùn)算限制
  2. 靜態(tài)初始化:確保所有字符串在編譯時(shí)確定,不影響運(yùn)行時(shí)性能
  3. CSS 動(dòng)畫:使用 CSS3 keyframes 實(shí)現(xiàn)數(shù)字彈跳效果
  4. 響應(yīng)式設(shè)計(jì):通過(guò)媒體查詢適配不同屏幕尺寸

八、擴(kuò)展思考

8.1 動(dòng)態(tài)錯(cuò)誤頁(yè)面

如果需要更靈活的錯(cuò)誤頁(yè)面(如從文件讀取模板),可以考慮:

static char *ngx_http_error_page_template = NULL;

static char* ngx_http_get_error_page(ngx_http_request_t *r, int code) {
    // 從配置文件讀取模板,動(dòng)態(tài)生成
}

8.2 性能考慮

靜態(tài)字符串?dāng)?shù)組的優(yōu)點(diǎn):

  • 零運(yùn)行時(shí)開(kāi)銷
  • 直接發(fā)送,無(wú)需額外內(nèi)存分配
  • CPU Cache 友好

動(dòng)態(tài)生成的優(yōu)點(diǎn):

  • 靈活性高,可支持更多定制
  • 便于維護(hù)和更新

根據(jù)實(shí)際需求選擇合適的方案。

總結(jié):通過(guò)巧妙地使用 C 語(yǔ)言宏,在不破壞 Nginx 原有架構(gòu)的前提下,為所有錯(cuò)誤頁(yè)面統(tǒng)一添加了現(xiàn)代化的 CSS 樣式和動(dòng)畫效果。這種方法既保持了高性能,又提升了用戶體驗(yàn),是一個(gè)典型的“零成本抽象”實(shí)踐。

以上就是Nginx修改默認(rèn)錯(cuò)誤頁(yè)面的代碼詳解的詳細(xì)內(nèi)容,更多關(guān)于Nginx修改默認(rèn)錯(cuò)誤頁(yè)面的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論

睢宁县| 若羌县| 鹤庆县| 千阳县| 安陆市| 化德县| 乐安县| 礼泉县| 吉首市| 张家口市| 商丘市| 古交市| 启东市| 鄂温| 清苑县| 溧水县| 伊金霍洛旗| 措勤县| 湟中县| 孟连| 吉林省| 沭阳县| 岳阳县| 南丰县| 九龙坡区| 白玉县| 苍山县| 维西| 柳河县| 沂南县| 荔浦县| 巴彦淖尔市| 高台县| 辉县市| 潞城市| 兴业县| 察雅县| 宿迁市| 建湖县| 锦屏县| 洛浦县|