litefs.error_pages 源代码

#!/usr/bin/env python
# coding: utf-8

"""
错误页面处理器

提供美观的错误页面渲染和自定义错误页面支持
"""

import os
from pathlib import Path
from typing import Dict, Optional, Tuple


[文档] class ErrorPageRenderer: """ 错误页面渲染器 支持默认错误页面和自定义错误页面 """ DEFAULT_ERROR_TEMPLATES = { 400: """ <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>400 - 错误的请求</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 20px; } .error-container { background: white; border-radius: 20px; box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3); padding: 60px 40px; text-align: center; max-width: 500px; width: 100%; } .error-code { font-size: 120px; font-weight: bold; color: #667eea; line-height: 1; margin-bottom: 20px; } .error-title { font-size: 28px; color: #333; margin-bottom: 15px; } .error-message { font-size: 16px; color: #666; line-height: 1.6; margin-bottom: 30px; } .error-detail { background: #f7f7f7; padding: 15px; border-radius: 8px; font-size: 14px; color: #888; margin-bottom: 30px; } .btn-home { display: inline-block; padding: 12px 30px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; text-decoration: none; border-radius: 25px; font-weight: 500; transition: transform 0.2s, box-shadow 0.2s; } .btn-home:hover { transform: translateY(-2px); box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4); } </style> </head> <body> <div class="error-container"> <div class="error-code">400</div> <h1 class="error-title">错误的请求</h1> <p class="error-message"> 服务器无法理解您的请求。请检查您的请求格式是否正确。 </p> <div class="error-detail"> 错误代码: 400 Bad Request<br> 说明: 客户端发送的请求有语法错误 </div> <a href="/" class="btn-home">返回首页</a> </div> </body> </html> """, 403: """ <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>403 - 禁止访问</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 20px; } .error-container { background: white; border-radius: 20px; box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3); padding: 60px 40px; text-align: center; max-width: 500px; width: 100%; } .error-icon { font-size: 80px; margin-bottom: 20px; } .error-code { font-size: 120px; font-weight: bold; color: #f5576c; line-height: 1; margin-bottom: 20px; } .error-title { font-size: 28px; color: #333; margin-bottom: 15px; } .error-message { font-size: 16px; color: #666; line-height: 1.6; margin-bottom: 30px; } .error-detail { background: #f7f7f7; padding: 15px; border-radius: 8px; font-size: 14px; color: #888; margin-bottom: 30px; } .btn-home { display: inline-block; padding: 12px 30px; background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); color: white; text-decoration: none; border-radius: 25px; font-weight: 500; transition: transform 0.2s, box-shadow 0.2s; } .btn-home:hover { transform: translateY(-2px); box-shadow: 0 5px 15px rgba(245, 87, 108, 0.4); } </style> </head> <body> <div class="error-container"> <div class="error-icon">🔒</div> <div class="error-code">403</div> <h1 class="error-title">禁止访问</h1> <p class="error-message"> 您没有权限访问此页面。如果您认为这是一个错误,请联系管理员。 </p> <div class="error-detail"> 错误代码: 403 Forbidden<br> 说明: 服务器拒绝执行此请求 </div> <a href="/" class="btn-home">返回首页</a> </div> </body> </html> """, 404: """ <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>404 - 页面未找到</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 20px; } .error-container { background: white; border-radius: 20px; box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3); padding: 60px 40px; text-align: center; max-width: 500px; width: 100%; } .error-icon { font-size: 80px; margin-bottom: 20px; } .error-code { font-size: 120px; font-weight: bold; color: #4facfe; line-height: 1; margin-bottom: 20px; } .error-title { font-size: 28px; color: #333; margin-bottom: 15px; } .error-message { font-size: 16px; color: #666; line-height: 1.6; margin-bottom: 30px; } .error-detail { background: #f7f7f7; padding: 15px; border-radius: 8px; font-size: 14px; color: #888; margin-bottom: 30px; } .btn-home { display: inline-block; padding: 12px 30px; background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); color: white; text-decoration: none; border-radius: 25px; font-weight: 500; transition: transform 0.2s, box-shadow 0.2s; } .btn-home:hover { transform: translateY(-2px); box-shadow: 0 5px 15px rgba(79, 172, 254, 0.4); } </style> </head> <body> <div class="error-container"> <div class="error-icon">🔍</div> <div class="error-code">404</div> <h1 class="error-title">页面未找到</h1> <p class="error-message"> 抱歉,您访问的页面不存在或已被删除。 </p> <div class="error-detail"> 错误代码: 404 Not Found<br> 说明: 服务器无法找到请求的资源 </div> <a href="/" class="btn-home">返回首页</a> </div> </body> </html> """, 500: """ <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>500 - 服务器内部错误</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; background: linear-gradient(135deg, #fa709a 0%, #fee140 100%); min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 20px; } .error-container { background: white; border-radius: 20px; box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3); padding: 60px 40px; text-align: center; max-width: 500px; width: 100%; } .error-icon { font-size: 80px; margin-bottom: 20px; } .error-code { font-size: 120px; font-weight: bold; color: #fa709a; line-height: 1; margin-bottom: 20px; } .error-title { font-size: 28px; color: #333; margin-bottom: 15px; } .error-message { font-size: 16px; color: #666; line-height: 1.6; margin-bottom: 30px; } .error-detail { background: #f7f7f7; padding: 15px; border-radius: 8px; font-size: 14px; color: #888; margin-bottom: 30px; } .btn-home { display: inline-block; padding: 12px 30px; background: linear-gradient(135deg, #fa709a 0%, #fee140 100%); color: white; text-decoration: none; border-radius: 25px; font-weight: 500; transition: transform 0.2s, box-shadow 0.2s; } .btn-home:hover { transform: translateY(-2px); box-shadow: 0 5px 15px rgba(250, 112, 154, 0.4); } </style> </head> <body> <div class="error-container"> <div class="error-icon">⚠️</div> <div class="error-code">500</div> <h1 class="error-title">服务器内部错误</h1> <p class="error-message"> 服务器遇到了一个意外情况,无法完成您的请求。请稍后再试。 </p> <div class="error-detail"> 错误代码: 500 Internal Server Error<br> 说明: 服务器遇到意外情况 </div> <a href="/" class="btn-home">返回首页</a> </div> </body> </html> """, 502: """ <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>502 - 网关错误</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; background: linear-gradient(135deg, #a8edea 0%, #fed6e3 100%); min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 20px; } .error-container { background: white; border-radius: 20px; box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3); padding: 60px 40px; text-align: center; max-width: 500px; width: 100%; } .error-icon { font-size: 80px; margin-bottom: 20px; } .error-code { font-size: 120px; font-weight: bold; color: #a8edea; line-height: 1; margin-bottom: 20px; } .error-title { font-size: 28px; color: #333; margin-bottom: 15px; } .error-message { font-size: 16px; color: #666; line-height: 1.6; margin-bottom: 30px; } .error-detail { background: #f7f7f7; padding: 15px; border-radius: 8px; font-size: 14px; color: #888; margin-bottom: 30px; } .btn-home { display: inline-block; padding: 12px 30px; background: linear-gradient(135deg, #a8edea 0%, #fed6e3 100%); color: white; text-decoration: none; border-radius: 25px; font-weight: 500; transition: transform 0.2s, box-shadow 0.2s; } .btn-home:hover { transform: translateY(-2px); box-shadow: 0 5px 15px rgba(168, 237, 234, 0.4); } </style> </head> <body> <div class="error-container"> <div class="error-icon">🌐</div> <div class="error-code">502</div> <h1 class="error-title">网关错误</h1> <p class="error-message"> 服务器作为网关或代理,从上游服务器收到了无效的响应。 </p> <div class="error-detail"> 错误代码: 502 Bad Gateway<br> 说明: 上游服务器响应无效 </div> <a href="/" class="btn-home">返回首页</a> </div> </body> </html> """, 503: """ <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>503 - 服务不可用</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; background: linear-gradient(135deg, #ff9a9e 0%, #fecfef 100%); min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 20px; } .error-container { background: white; border-radius: 20px; box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3); padding: 60px 40px; text-align: center; max-width: 500px; width: 100%; } .error-icon { font-size: 80px; margin-bottom: 20px; } .error-code { font-size: 120px; font-weight: bold; color: #ff9a9e; line-height: 1; margin-bottom: 20px; } .error-title { font-size: 28px; color: #333; margin-bottom: 15px; } .error-message { font-size: 16px; color: #666; line-height: 1.6; margin-bottom: 30px; } .error-detail { background: #f7f7f7; padding: 15px; border-radius: 8px; font-size: 14px; color: #888; margin-bottom: 30px; } .btn-home { display: inline-block; padding: 12px 30px; background: linear-gradient(135deg, #ff9a9e 0%, #fecfef 100%); color: white; text-decoration: none; border-radius: 25px; font-weight: 500; transition: transform 0.2s, box-shadow 0.2s; } .btn-home:hover { transform: translateY(-2px); box-shadow: 0 5px 15px rgba(255, 154, 158, 0.4); } </style> </head> <body> <div class="error-container"> <div class="error-icon">🔧</div> <div class="error-code">503</div> <h1 class="error-title">服务不可用</h1> <p class="error-message"> 服务器当前无法处理请求,可能正在进行维护或过载。请稍后再试。 </p> <div class="error-detail"> 错误代码: 503 Service Unavailable<br> 说明: 服务器暂时无法处理请求 </div> <a href="/" class="btn-home">返回首页</a> </div> </body> </html> """, 504: """ <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>504 - 网关超时</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; background: linear-gradient(135deg, #fbc2eb 0%, #a6c1ee 100%); min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 20px; } .error-container { background: white; border-radius: 20px; box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3); padding: 60px 40px; text-align: center; max-width: 500px; width: 100%; } .error-icon { font-size: 80px; margin-bottom: 20px; } .error-code { font-size: 120px; font-weight: bold; color: #fbc2eb; line-height: 1; margin-bottom: 20px; } .error-title { font-size: 28px; color: #333; margin-bottom: 15px; } .error-message { font-size: 16px; color: #666; line-height: 1.6; margin-bottom: 30px; } .error-detail { background: #f7f7f7; padding: 15px; border-radius: 8px; font-size: 14px; color: #888; margin-bottom: 30px; } .btn-home { display: inline-block; padding: 12px 30px; background: linear-gradient(135deg, #fbc2eb 0%, #a6c1ee 100%); color: white; text-decoration: none; border-radius: 25px; font-weight: 500; transition: transform 0.2s, box-shadow 0.2s; } .btn-home:hover { transform: translateY(-2px); box-shadow: 0 5px 15px rgba(251, 194, 235, 0.4); } </style> </head> <body> <div class="error-container"> <div class="error-icon">⏱️</div> <div class="error-code">504</div> <h1 class="error-title">网关超时</h1> <p class="error-message"> 服务器作为网关或代理,未及时从上游服务器收到响应。 </p> <div class="error-detail"> 错误代码: 504 Gateway Timeout<br> 说明: 上游服务器响应超时 </div> <a href="/" class="btn-home">返回首页</a> </div> </body> </html> """, } def __init__(self, custom_error_dir: Optional[str] = None): """ 初始化错误页面渲染器 Args: custom_error_dir: 自定义错误页面目录路径 """ self._custom_error_dir = custom_error_dir self._custom_templates: Dict[int, str] = {} if custom_error_dir: self._load_custom_templates() def _load_custom_templates(self): """加载自定义错误页面模板""" if not self._custom_error_dir: return error_dir = Path(self._custom_error_dir) if not error_dir.exists(): return for error_code in [400, 403, 404, 500, 502, 503, 504]: template_file = error_dir / f"{error_code}.html" if template_file.exists(): with open(template_file, 'r', encoding='utf-8') as f: self._custom_templates[error_code] = f.read()
[文档] def render_error_page( self, status_code: int, message: Optional[str] = None, detail: Optional[str] = None ) -> str: """ 渲染错误页面 Args: status_code: HTTP 状态码 message: 自定义错误消息 detail: 自定义错误详情 Returns: HTML 错误页面 """ if status_code in self._custom_templates: template = self._custom_templates[status_code] elif status_code in self.DEFAULT_ERROR_TEMPLATES: template = self.DEFAULT_ERROR_TEMPLATES[status_code] else: template = self.DEFAULT_ERROR_TEMPLATES[500] if message: template = template.replace("错误代码: 500 Internal Server Error", f"错误信息: {message}") if detail: template = template.replace("说明: 服务器遇到意外情况", f"说明: {detail}") return template
[文档] def get_error_page( self, status_code: int, message: Optional[str] = None, detail: Optional[str] = None ) -> Tuple[int, str, str]: """ 获取错误页面 Args: status_code: HTTP 状态码 message: 自定义错误消息 detail: 自定义错误详情 Returns: (状态码, 内容类型, HTML 内容) """ content = self.render_error_page(status_code, message, detail) return status_code, "text/html; charset=utf-8", content
__all__ = [ "ErrorPageRenderer", ]