前言
大家好,我是老馬。很高興遇到你。
我們為 java 開發者實現了 java 版本的 nginx
https://github.com/houbb/nginx4j
如果你想知道 servlet 如何處理的,可以參考我的另一個項目:
手寫從零實現簡易版 tomcat minicat
手寫 nginx 系列
如果你對 nginx 原理感興趣,可以閱讀:
從零手寫實現 nginx-01-為什么不能有 java 版本的 nginx?
從零手寫實現 nginx-02-nginx 的核心能力
從零手寫實現 nginx-03-nginx 基于 Netty 實現
從零手寫實現 nginx-04-基于 netty http 出入參優化處理
從零手寫實現 nginx-05-MIME類型(Multipurpose Internet Mail Extensions,多用途互聯網郵件擴展類型)
從零手寫實現 nginx-06-文件夾自動索引
從零手寫實現 nginx-07-大文件下載
從零手寫實現 nginx-08-范圍查詢
從零手寫實現 nginx-09-文件壓縮
從零手寫實現 nginx-10-sendfile 零拷貝
從零手寫實現 nginx-11-file+range 合并
從零手寫實現 nginx-12-keep-alive 連接復用
從零手寫實現 nginx-13-nginx.conf 配置文件介紹
從零手寫實現 nginx-14-nginx.conf 和 hocon 格式有關系嗎?
從零手寫實現 nginx-15-nginx.conf 如何通過 java 解析處理?
從零手寫實現 nginx-16-nginx 支持配置多個 server
從零手寫實現 nginx-17-nginx 默認配置優化
從零手寫實現 nginx-18-nginx 請求頭+響應頭操作
從零手寫實現 nginx-19-nginx cors
從零手寫實現 nginx-20-nginx 占位符 placeholder
從零手寫實現 nginx-21-nginx modules 模塊信息概覽
從零手寫實現 nginx-22-nginx modules 分模塊加載優化
從零手寫實現 nginx-23-nginx cookie 的操作處理
從零手寫實現 nginx-24-nginx IF 指令
從零手寫實現 nginx-25-nginx map 指令
從零手寫實現 nginx-26-nginx rewrite 指令
從零手寫實現 nginx-27-nginx return 指令
從零手寫實現 nginx-28-nginx error_pages 指令
從零手寫實現 nginx-29-nginx try_files 指令
nginx 的 error_page 指令
nginx
的 error_page
指令用于定義自定義錯誤頁面。
當服務器遇到錯誤時,nginx
會根據配置返回自定義的錯誤頁面,而不是默認的錯誤頁面。這在提高用戶體驗和品牌一致性方面非常有用。
error_page
指令語法
error_page code [code ...] [=[response]] uri;
code
:HTTP 狀態碼,可以是單個狀態碼或多個狀態碼,表示哪些錯誤狀態碼會觸發自定義錯誤頁面。=[response]
:可選參數,表示在返回自定義錯誤頁面時,是否改變 HTTP 響應狀態碼。uri
:指定自定義錯誤頁面的 URI,可以是相對路徑或絕對路徑。
示例和解釋
基本用法
- 單個錯誤代碼
error_page 404 /custom_404.html;
當服務器返回 404 錯誤時,nginx
會返回 /custom_404.html
這個頁面。
- 多個錯誤代碼
error_page 500 502 503 504 /custom_5xx.html;
當服務器返回 500, 502, 503 或 504 錯誤時,nginx
會返回 /custom_5xx.html
這個頁面。
改變響應狀態碼
有時,你可能希望在重定向到自定義錯誤頁面時,改變 HTTP 響應狀態碼。例如,將 404 錯誤重定向到一個頁面,但返回 200 狀態碼。
error_page 404 =200 /custom_404.html;
當服務器返回 404 錯誤時,nginx
會返回 /custom_404.html
頁面,但 HTTP 響應狀態碼是 200。
使用內部重定向
可以使用 @named_location
來處理錯誤。這個方法允許你將錯誤處理邏輯封裝在一個內部位置。
error_page 500 502 503 504 /50x.html;location = /50x.html {root /usr/share/nginx/html;
}
當服務器返回 500, 502, 503 或 504 錯誤時,nginx
會將請求內部重定向到 /50x.html
。此時,/50x.html
頁面存放在 /usr/share/nginx/html
目錄下。
高級用法
自定義錯誤頁面與代理服務器結合
當你使用 nginx
作為反向代理服務器時,也可以定義自定義錯誤頁面。例如,當后端服務器不可用時,顯示友好的錯誤頁面。
server {listen 80;server_name example.com;location / {proxy_pass http://backend;proxy_intercept_errors on;error_page 500 502 503 504 /custom_50x.html;}location = /custom_50x.html {root /usr/share/nginx/html;}
}
在這個例子中,當后端服務器返回 500, 502, 503 或 504 錯誤時,nginx
會攔截這些錯誤并返回自定義的 /custom_50x.html
頁面。
常見錯誤代碼
以下是一些常見的 HTTP 錯誤代碼及其含義:
400
:Bad Request(錯誤請求)401
:Unauthorized(未授權)403
:Forbidden(禁止訪問)404
:Not Found(未找到)500
:Internal Server Error(內部服務器錯誤)502
:Bad Gateway(錯誤網關)503
:Service Unavailable(服務不可用)504
:Gateway Timeout(網關超時)
示例:完整的 Nginx 配置文件
server {listen 80;server_name example.com;location / {try_files $uri $uri/ =404;}error_page 404 /custom_404.html;error_page 500 502 503 504 /custom_50x.html;location = /custom_404.html {root /usr/share/nginx/html;}location = /custom_50x.html {root /usr/share/nginx/html;}
}
結論
nginx
的 error_page
指令非常靈活,允許你根據需要自定義錯誤頁面,以改善用戶體驗和提供更友好的錯誤消息。
通過使用該指令,你可以輕松地創建品牌一致的錯誤頁面,并將其集成到現有的 nginx
配置中。
java error_page
error_page 指令的處理
package com.github.houbb.nginx4j.config.param.impl.dispatch;import com.github.houbb.heaven.util.util.CollectionUtil;
import com.github.houbb.log.integration.core.Log;
import com.github.houbb.log.integration.core.LogFactory;
import com.github.houbb.nginx4j.config.NginxCommonConfigEntry;
import com.github.houbb.nginx4j.config.NginxConfig;
import com.github.houbb.nginx4j.config.param.AbstractNginxParamLifecycleDispatch;
import com.github.houbb.nginx4j.exception.Nginx4jException;
import com.github.houbb.nginx4j.support.errorpage.INginxErrorPageManage;
import com.github.houbb.nginx4j.support.request.dispatch.NginxRequestDispatchContext;import java.util.List;/*** 參數處理類 響應頭處理** @since 0.25.0* @author 老馬嘯西風*/
public class NginxParamHandleErrorPage extends AbstractNginxParamLifecycleDispatch {private static final Log logger = LogFactory.getLog(NginxParamHandleErrorPage.class);@Overridepublic boolean doBeforeDispatch(NginxCommonConfigEntry configParam, NginxRequestDispatchContext context) {List<String> values = configParam.getValues();if(CollectionUtil.isEmpty(values) || values.size() < 2) {throw new Nginx4jException("error_page 必須包含2個參數");}NginxConfig nginxConfig = context.getNginxConfig();INginxErrorPageManage nginxErrorPageManage = nginxConfig.getNginxErrorPageManage();// 直接拆分String lastHtml = values.get(values.size()-1);for(int i = 0; i < values.size()-1; i++) {String code = values.get(i);nginxErrorPageManage.register(code, lastHtml);}return true;}@Overridepublic boolean doAfterDispatch(NginxCommonConfigEntry configParam, NginxRequestDispatchContext context) {return true;}@Overrideprotected String getKey(NginxCommonConfigEntry configParam, NginxRequestDispatchContext context) {return "error_page";}@Overridepublic String directiveName() {return "error_page";}}
定義 error_page 映射關系的存儲
package com.github.houbb.nginx4j.support.errorpage;import com.github.houbb.log.integration.core.Log;
import com.github.houbb.log.integration.core.LogFactory;import java.util.HashMap;
import java.util.Map;/*** @since 0.25.0* @author 老馬嘯西風*/
public class NginxErrorPageManageDefault implements INginxErrorPageManage {private static final Log logger = LogFactory.getLog(NginxErrorPageManageDefault.class);private final Map<String, String> map = new HashMap<>();@Overridepublic void register(String code, String htmlPath) {map.put(code, htmlPath);logger.info("error_page register code={}, path={}", code, htmlPath);}@Overridepublic String getPath(String code) {String path = map.get(code);logger.info("error_page register code={}, path={}", code, path);return path;}}