美文网首页
从零手写实现 nginx-28-error pages 指令

从零手写实现 nginx-28-error pages 指令

作者: 老马啸西风2020 | 来源:发表于2024-07-13 22:29 被阅读0次

    前言

    大家好,我是老马。很高兴遇到你。

    我们为 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 指令

    nginxerror_page 指令用于定义自定义错误页面。

    当服务器遇到错误时,nginx 会根据配置返回自定义的错误页面,而不是默认的错误页面。这在提高用户体验和品牌一致性方面非常有用。

    error_page 指令语法

    error_page code [code ...] [=[response]] uri;
    
    • code:HTTP 状态码,可以是单个状态码或多个状态码,表示哪些错误状态码会触发自定义错误页面。
    • =[response]:可选参数,表示在返回自定义错误页面时,是否改变 HTTP 响应状态码。
    • uri:指定自定义错误页面的 URI,可以是相对路径或绝对路径。

    示例和解释

    基本用法

    1. 单个错误代码
    error_page 404 /custom_404.html;
    

    当服务器返回 404 错误时,nginx 会返回 /custom_404.html 这个页面。

    1. 多个错误代码
    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;
        }
    }
    

    结论

    nginxerror_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);
    
    
        @Override
        public 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;
        }
    
        @Override
        public boolean doAfterDispatch(NginxCommonConfigEntry configParam, NginxRequestDispatchContext context) {
            return true;
        }
    
        @Override
        protected String getKey(NginxCommonConfigEntry configParam, NginxRequestDispatchContext context) {
            return "error_page";
        }
    
        @Override
        public 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<>();
    
        @Override
        public void register(String code, String htmlPath) {
            map.put(code, htmlPath);
            logger.info("error_page register code={}, path={}", code, htmlPath);
        }
    
        @Override
        public String getPath(String code) {
            String path = map.get(code);
    
            logger.info("error_page register code={}, path={}", code, path);
            return path;
        }
    
    }
    

    相关文章

      网友评论

          本文标题:从零手写实现 nginx-28-error pages 指令

          本文链接:https://www.haomeiwen.com/subject/vdbqhjtx.html