Docker 容器化完全指南

什么是 Docker? Docker 是一个开源的容器化平台,用于打包、分发和运行应用程序。它通过将应用程序及其依赖项打包到一个轻量级的容器中,确保应用在任何环境中都能一致地运行。 Docker 的核心概念 镜像(Image) 镜像是一个轻量级的、独立的、可执行的软件包,包含运行应用所需的所有内容(代码、运行时、系统工具、库等)。 容器(Container) 容器是镜像的运行实例。可以把镜像看作是类,容器就是对象。 仓库(Repository) 存储镜像的地方。Docker Hub 是最大的公共镜像仓库。 Dockerfile 用于定义如何构建镜像的文本文件。 Docker 安装 Windows 和 Mac 下载 Docker Desktop:https://www.docker.com/products/docker-desktop Linux(Ubuntu) # 更新包管理器 sudo apt-get update # 安装 Docker sudo apt-get install docker.io # 启动 Docker 服务 sudo systemctl start docker # 验证安装 docker --version 基础命令 镜像操作 # 拉取镜像 docker pull ubuntu:latest # 列出本地镜像 docker images # 删除镜像 docker rmi image_id # 搜索镜像 docker search nginx 容器操作 # 运行容器 docker run -d --name my-container ubuntu:latest # 列出运行中的容器 docker ps # 列出所有容器(包括已停止的) docker ps -a # 停止容器 docker stop container_id # 启动容器 docker start container_id # 删除容器 docker rm container_id # 查看容器日志 docker logs container_id # 进入容器 docker exec -it container_id /bin/bash 编写 Dockerfile # 使用基础镜像 FROM python:3.9-slim # 设置工作目录 WORKDIR /app # 复制文件 COPY . . # 安装依赖 RUN pip install -r requirements.txt # 暴露端口 EXPOSE 5000 # 运行应用 CMD ["python", "app.py"] 构建和运行镜像 # 构建镜像 docker build -t my-app:1.0 . # 运行容器 docker run -d -p 5000:5000 --name my-app-container my-app:1.0 # 查看容器状态 docker ps # 查看日志 docker logs my-app-container Docker Compose Docker Compose 用于定义和运行多容器应用。 ...

2025-12-15 · 275 字 · MagicBude

Git 进阶技巧和工作流

介绍 Git 基础知识很重要,但掌握进阶技巧能让你的开发工作流更高效。本文介绍一些实用的 Git 进阶技巧。 分支管理 创建和切换分支 # 创建新分支 git branch feature/new-feature # 切换分支 git checkout feature/new-feature # 创建并切换分支(简写) git checkout -b feature/new-feature # 或使用新语法 git switch -c feature/new-feature 删除分支 # 删除本地分支 git branch -d feature/new-feature # 强制删除分支 git branch -D feature/new-feature # 删除远程分支 git push origin --delete feature/new-feature 分支重命名 # 重命名当前分支 git branch -m new-name # 重命名其他分支 git branch -m old-name new-name # 推送重命名后的分支 git push origin new-name git push origin --delete old-name 变基(Rebase) 变基是一种整理提交历史的强大工具。 ...

2025-12-15 · 504 字 · MagicBude

前端性能优化完全指南

为什么性能很重要? 网站性能直接影响用户体验和搜索引擎排名。研究表明,页面加载时间每增加 1 秒,转化率就会下降 7%。 性能指标 核心 Web 指标(Core Web Vitals) LCP(Largest Contentful Paint) - 最大内容绘制 衡量页面主要内容加载的速度 目标:< 2.5 秒 FID(First Input Delay) - 首次输入延迟 衡量用户交互的响应速度 目标:< 100 毫秒 CLS(Cumulative Layout Shift) - 累积布局偏移 衡量页面稳定性 目标:< 0.1 其他重要指标 TTFB(Time to First Byte) - 首字节时间 FCP(First Contentful Paint) - 首次内容绘制 TTI(Time to Interactive) - 可交互时间 性能优化策略 1. 资源优化 图片优化 // 使用现代格式(WebP) <picture> <source srcset="image.webp" type="image/webp"> <img src="image.jpg" alt="description"> </picture> // 使用响应式图片 <img srcset="small.jpg 480w, medium.jpg 800w, large.jpg 1200w" sizes="(max-width: 600px) 480px, 800px" src="medium.jpg" alt="description"> // 使用 CDN 和图片压缩服务 // 例如:Cloudinary, ImageKit 等 CSS 优化 /* 移除未使用的 CSS */ /* 使用 PurgeCSS 或 Tailwind CSS 的 purge 功能 */ /* 内联关键 CSS */ <style> /* 首屏必需的 CSS */ </style> <link rel="stylesheet" href="non-critical.css" media="print" onload="this.media='all'"> /* 使用 CSS 变量减少重复 */ :root { --primary-color: #007bff; --spacing-unit: 8px; } JavaScript 优化 // 代码分割 import { lazy, Suspense } from 'react'; const HeavyComponent = lazy(() => import('./HeavyComponent')); // 延迟加载非关键脚本 <script defer src="analytics.js"></script> <script async src="ads.js"></script> // 使用 Web Workers 处理耗时任务 const worker = new Worker('worker.js'); worker.postMessage({ data: largeData }); worker.onmessage = (e) => { console.log('Result:', e.data); }; 2. 缓存策略 浏览器缓存 // 设置缓存头 // HTTP 响应头 Cache-Control: max-age=31536000 // 1 年 Cache-Control: max-age=3600, must-revalidate // 1 小时,需要验证 // 使用 ETag 进行条件请求 If-None-Match: "33a64df..." Service Worker 缓存 // service-worker.js const CACHE_NAME = 'v1'; const urlsToCache = [ '/', '/styles/main.css', '/script/main.js' ]; self.addEventListener('install', (event) => { event.waitUntil( caches.open(CACHE_NAME).then((cache) => { return cache.addAll(urlsToCache); }) ); }); self.addEventListener('fetch', (event) => { event.respondWith( caches.match(event.request).then((response) => { return response || fetch(event.request); }) ); }); 3. 代码分割和懒加载 // 路由级别的代码分割 const routes = [ { path: '/', component: () => import('./pages/Home') }, { path: '/about', component: () => import('./pages/About') } ]; // 组件级别的懒加载 const LazyImage = lazy(() => import('./LazyImage')); // 使用 Intersection Observer 实现图片懒加载 const imageObserver = new IntersectionObserver((entries) => { entries.forEach((entry) => { if (entry.isIntersecting) { const img = entry.target; img.src = img.dataset.src; imageObserver.unobserve(img); } }); }); document.querySelectorAll('img[data-src]').forEach((img) => { imageObserver.observe(img); }); 4. 网络优化 DNS 预解析 <link rel="dns-prefetch" href="https://example.com"> <link rel="preconnect" href="https://fonts.googleapis.com"> 资源预加载 <!-- 预加载关键资源 --> <link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin> <link rel="preload" href="critical.js" as="script"> <!-- 预连接 --> <link rel="preconnect" href="https://api.example.com"> <!-- 预获取非关键资源 --> <link rel="prefetch" href="next-page.js"> 使用 CDN // 使用 CDN 分发静态资源 // 例如:Cloudflare, AWS CloudFront, Akamai 等 // 在 HTML 中使用 CDN URL <script src="https://cdn.example.com/script.js"></script> <link rel="stylesheet" href="https://cdn.example.com/style.css"> 5. 渲染优化 避免重排和重绘 // 不好的做法 - 多次重排 for (let i = 0; i < 100; i++) { element.style.width = element.offsetWidth + 1 + 'px'; } // 好的做法 - 批量修改 const width = element.offsetWidth; for (let i = 0; i < 100; i++) { element.style.width = (width + i) + 'px'; } // 或使用 requestAnimationFrame let width = element.offsetWidth; function update() { element.style.width = width + 'px'; width++; } requestAnimationFrame(update); 虚拟滚动 // 只渲染可见的列表项 import { FixedSizeList } from 'react-window'; const Row = ({ index, style }) => ( <div style={style}>Item {index}</div> ); <FixedSizeList height={600} itemCount={1000} itemSize={35} width="100%" > {Row} </FixedSizeList> 6. 监控和分析 使用 Web Vitals 库 import { getCLS, getFID, getFCP, getLCP, getTTFB } from 'web-vitals'; getCLS(console.log); getFID(console.log); getFCP(console.log); getLCP(console.log); getTTFB(console.log); 性能监控 API // 使用 Performance API const perfData = window.performance.timing; const pageLoadTime = perfData.loadEventEnd - perfData.navigationStart; console.log('Page load time:', pageLoadTime); // 使用 PerformanceObserver const observer = new PerformanceObserver((list) => { for (const entry of list.getEntries()) { console.log('Entry:', entry); } }); observer.observe({ entryTypes: ['navigation', 'resource', 'paint'] }); 性能优化检查清单 图片已优化和压缩 使用了现代图片格式(WebP) CSS 已最小化和分割 JavaScript 已分割和懒加载 关键资源已预加载 使用了 Service Worker 缓存 已配置 CDN 已移除未使用的代码 已启用 Gzip 压缩 已配置浏览器缓存 已优化字体加载 已测试核心 Web 指标 性能测试工具 Google PageSpeed Insights - https://pagespeed.web.dev WebPageTest - https://www.webpagetest.org Lighthouse - Chrome DevTools 内置 GTmetrix - https://gtmetrix.com 总结 前端性能优化是一个持续的过程。通过实施这些优化策略,你可以显著提升网站的加载速度和用户体验。记住,性能优化的关键是测量、优化、验证。

2025-12-15 · 585 字 · MagicBude

正则表达式完全指南

什么是正则表达式? 正则表达式(Regular Expression,简称 Regex)是一种用于匹配字符串的强大工具。它使用特定的语法来描述字符串的模式,可以用于搜索、替换、验证等操作。 基础语法 字符类 . 匹配任意单个字符(除了换行符) \d 匹配数字 [0-9] \D 匹配非数字 \w 匹配字母、数字、下划线 [a-zA-Z0-9_] \W 匹配非字母、数字、下划线 \s 匹配空白字符(空格、制表符、换行符等) \S 匹配非空白字符 [abc] 匹配 a、b 或 c [a-z] 匹配 a 到 z 的任意字符 [^abc] 匹配除了 a、b、c 之外的任意字符 量词 * 匹配 0 次或多次 + 匹配 1 次或多次 ? 匹配 0 次或 1 次 {n} 匹配恰好 n 次 {n,} 匹配至少 n 次 {n,m} 匹配 n 到 m 次 锚点 ^ 匹配字符串的开始 $ 匹配字符串的结束 \b 匹配单词边界 \B 匹配非单词边界 分组和引用 (abc) 分组,捕获 abc (?:abc) 非捕获分组 (a|b) 匹配 a 或 b \1 引用第一个捕获组 常见模式 验证电子邮件 ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ 验证电话号码(中国) ^1[3-9]\d{9}$ 验证 URL ^https?://[^\s/$.?#].[^\s]*$ 验证 IP 地址 ^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$ 验证身份证号(简化版) ^\d{17}[\dXx]$ 匹配 HTML 标签 <([a-z]+)([^>]*)>(.*?)</\1> JavaScript 中的正则表达式 创建正则表达式 // 字面量方式 const regex1 = /hello/i; // 构造函数方式 const regex2 = new RegExp('hello', 'i'); 常用方法 test() - 测试是否匹配 const regex = /hello/i; console.log(regex.test('Hello World')); // true console.log(regex.test('Goodbye')); // false exec() - 执行匹配 const regex = /(\d+)-(\d+)-(\d+)/; const result = regex.exec('2025-12-15'); console.log(result[0]); // "2025-12-15" console.log(result[1]); // "2025" console.log(result[2]); // "12" console.log(result[3]); // "15" match() - 字符串方法 const str = 'The year is 2025'; const matches = str.match(/\d+/g); console.log(matches); // ["2025"] replace() - 替换 const str = 'Hello World'; const result = str.replace(/world/i, 'JavaScript'); console.log(result); // "Hello JavaScript" // 使用捕获组 const date = '2025-12-15'; const formatted = date.replace(/(\d+)-(\d+)-(\d+)/, '$3/$2/$1'); console.log(formatted); // "15/12/2025" split() - 分割 const str = 'apple,banana;orange:grape'; const fruits = str.split(/[,;:]/); console.log(fruits); // ["apple", "banana", "orange", "grape"] search() - 查找位置 const str = 'Hello World'; const index = str.search(/world/i); console.log(index); // 6 高级用法 前向断言和后向断言 (?=pattern) 正向前向断言 - 匹配后面跟着 pattern 的位置 (?!pattern) 负向前向断言 - 匹配后面不跟着 pattern 的位置 (?<=pattern) 正向后向断言 - 匹配前面跟着 pattern 的位置 (?<!pattern) 负向后向断言 - 匹配前面不跟着 pattern 的位置 示例 // 匹配不是 .jpg 的文件名 const regex = /\w+(?!\.jpg)$/i; // 匹配价格(前面有 $ 符号) const regex = /(?<=\$)\d+(\.\d{2})?/; // 在 JavaScript 中使用 const str = '$100 and $50.99'; const prices = str.match(/(?<=\$)\d+(\.\d{2})?/g); console.log(prices); // ["100", "50.99"] 贪心和非贪心匹配 const str = '<div>Hello</div><div>World</div>'; // 贪心匹配(默认) const greedy = str.match(/<div>.*<\/div>/); console.log(greedy[0]); // "<div>Hello</div><div>World</div>" // 非贪心匹配 const nonGreedy = str.match(/<div>.*?<\/div>/g); console.log(nonGreedy); // ["<div>Hello</div>", "<div>World</div>"] 实用示例 验证密码强度 function validatePassword(password) { const regex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/; return regex.test(password); } console.log(validatePassword('Weak123')); // false console.log(validatePassword('Strong@123')); // true 提取 URL 参数 function getUrlParams(url) { const params = {}; const regex = /[?&]([^=]+)=([^&]*)/g; let match; while ((match = regex.exec(url)) !== null) { params[match[1]] = decodeURIComponent(match[2]); } return params; } const url = 'https://example.com?name=John&age=30'; console.log(getUrlParams(url)); // { name: 'John', age: '30' } 驼峰转下划线 function camelToSnake(str) { return str.replace(/([A-Z])/g, '_$1').toLowerCase(); } console.log(camelToSnake('getUserName')); // "get_user_name" 下划线转驼峰 function snakeToCamel(str) { return str.replace(/_([a-z])/g, (match, letter) => letter.toUpperCase()); } console.log(snakeToCamel('get_user_name')); // "getUserName" 移除 HTML 标签 function stripHtmlTags(html) { return html.replace(/<[^>]*>/g, ''); } console.log(stripHtmlTags('<p>Hello <b>World</b></p>')); // "Hello World" 正则表达式标志 g 全局匹配(找到所有匹配项) i 不区分大小写 m 多行匹配 s 使 . 匹配换行符 u Unicode 模式 y 粘性匹配 性能优化建议 避免过度回溯 - 使用具体的模式而不是过于宽泛的模式 使用非捕获分组 - 如果不需要捕获,使用 (?:...) 而不是 (...) 避免嵌套量词 - 如 (a+)+ 可能导致性能问题 使用字符类而不是交替 - [abc] 比 (a|b|c) 更快 预编译正则表达式 - 避免在循环中重复创建正则表达式 常见错误 // 错误:忘记转义特殊字符 const regex = /\./; // 匹配任意字符,不是点号 // 正确:转义点号 const regex = /\./; // 匹配点号 // 错误:在字符类中不需要转义某些字符 const regex = /[\d\-]/; // 在字符类中,- 应该在开头或结尾 // 正确 const regex = /[\d-]/; // 或 /[-\d]/ 在线工具 Regex101 - https://regex101.com RegexPal - https://www.regexpal.com Regex Tester - https://www.regextester.com 总结 正则表达式是文本处理的强大工具。虽然学习曲线陡峭,但掌握它能大大提高开发效率。记住,实践是学习正则表达式的最好方法。

2025-12-15 · 514 字 · MagicBude

API 设计最佳实践

什么是好的 API? 好的 API 应该是: 易于理解 - 清晰的命名和文档 易于使用 - 一致的设计模式 易于维护 - 良好的版本控制和向后兼容性 安全可靠 - 身份验证、授权、速率限制 高性能 - 快速响应和高效的资源使用 RESTful API 原则 基本概念 REST(Representational State Transfer)是一种架构风格,基于以下原则: 客户端-服务器架构 - 分离关注点 无状态 - 每个请求包含所有必要信息 可缓存 - 响应应该定义自己是否可缓存 统一接口 - 一致的 API 设计 分层系统 - 客户端不知道是否直接连接到最终服务器 HTTP 方法 GET 获取资源 POST 创建新资源 PUT 替换整个资源 PATCH 部分更新资源 DELETE 删除资源 HEAD 获取资源元数据(不返回响应体) OPTIONS 获取资源的通信选项 资源和 URL 设计 好的设计: GET /api/v1/users 获取用户列表 POST /api/v1/users 创建新用户 GET /api/v1/users/:id 获取特定用户 PUT /api/v1/users/:id 更新用户 DELETE /api/v1/users/:id 删除用户 GET /api/v1/users/:id/posts 获取用户的文章 不好的设计: GET /api/getUser GET /api/createUser GET /api/updateUser?id=1 GET /api/deleteUser?id=1 关键原则 使用名词而不是动词 - /users 而不是 /getUsers 使用复数形式 - /users 而不是 /user 使用小写 - /api/users 而不是 /api/Users 使用连字符分隔单词 - /user-profiles 而不是 /userProfiles 避免深层嵌套 - 最多两层 /users/:id/posts 版本控制 URL 版本控制(推荐) /api/v1/users /api/v2/users 请求头版本控制 GET /api/users Accept: application/vnd.myapi.v1+json 查询参数版本控制 GET /api/users?version=1 请求和响应格式 请求示例 POST /api/v1/users Content-Type: application/json { "name": "John Doe", "email": "john@example.com", "age": 30 } 成功响应示例 HTTP/1.1 201 Created Content-Type: application/json { "id": 1, "name": "John Doe", "email": "john@example.com", "age": 30, "createdAt": "2025-12-15T10:00:00Z" } 响应结构 { "status": "success", "code": 200, "data": { "id": 1, "name": "John Doe" }, "message": "User retrieved successfully" } HTTP 状态码 2xx 成功 200 OK 请求成功 201 Created 资源创建成功 204 No Content 请求成功但无返回内容 3xx 重定向 301 Moved Permanently 永久重定向 302 Found 临时重定向 304 Not Modified 资源未修改 4xx 客户端错误 400 Bad Request 请求格式错误 401 Unauthorized 需要身份验证 403 Forbidden 无权限访问 404 Not Found 资源不存在 409 Conflict 请求冲突 422 Unprocessable Entity 请求格式正确但包含语义错误 429 Too Many Requests 请求过于频繁 5xx 服务器错误 500 Internal Server Error 服务器内部错误 502 Bad Gateway 网关错误 503 Service Unavailable 服务不可用 错误处理 统一的错误响应格式 { "status": "error", "code": 400, "error": { "type": "ValidationError", "message": "Invalid input", "details": [ { "field": "email", "message": "Invalid email format" }, { "field": "age", "message": "Age must be at least 18" } ] } } 错误处理最佳实践 // Express.js 示例 app.post('/api/v1/users', (req, res) => { try { // 验证输入 if (!req.body.email) { return res.status(400).json({ status: 'error', code: 400, error: { type: 'ValidationError', message: 'Email is required' } }); } // 处理请求 const user = createUser(req.body); res.status(201).json({ status: 'success', code: 201, data: user }); } catch (error) { res.status(500).json({ status: 'error', code: 500, error: { type: 'InternalServerError', message: 'An unexpected error occurred' } }); } }); 分页和过滤 分页 GET /api/v1/users?page=1&limit=10 GET /api/v1/users?offset=0&limit=10 响应示例 { "status": "success", "data": [...], "pagination": { "page": 1, "limit": 10, "total": 100, "totalPages": 10 } } 过滤和排序 GET /api/v1/users?status=active&sort=name&order=asc GET /api/v1/users?role=admin&createdAfter=2025-01-01 身份验证和授权 JWT 身份验证 // 登录端点 POST /api/v1/auth/login { "email": "user@example.com", "password": "password123" } // 响应 { "status": "success", "data": { "token": "eyJhbGciOiJIUzI1NiIs...", "expiresIn": 3600 } } // 使用 token 访问受保护的资源 GET /api/v1/users/me Authorization: Bearer eyJhbGciOiJIUzI1NiIs... 速率限制 HTTP/1.1 200 OK X-RateLimit-Limit: 100 X-RateLimit-Remaining: 99 X-RateLimit-Reset: 1640000000 API 文档 使用 OpenAPI/Swagger openapi: 3.0.0 info: title: User API version: 1.0.0 paths: /api/v1/users: get: summary: Get all users parameters: - name: page in: query schema: type: integer responses: '200': description: List of users content: application/json: schema: type: array items: $ref: '#/components/schemas/User' post: summary: Create a new user requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UserInput' responses: '201': description: User created 向后兼容性 版本控制策略 添加新字段 - 安全,客户端可以忽略 重命名字段 - 保留旧字段,添加新字段 删除字段 - 先弃用,后删除 更改字段类型 - 创建新版本 弃用策略 HTTP/1.1 200 OK Deprecation: true Sunset: Sun, 31 Dec 2025 23:59:59 GMT Link: </api/v2/users>; rel="successor-version" 安全最佳实践 使用 HTTPS - 加密传输 验证输入 - 防止注入攻击 实施速率限制 - 防止滥用 使用 CORS - 控制跨域访问 实施身份验证 - 保护敏感资源 记录和监控 - 追踪异常活动 定期更新依赖 - 修复安全漏洞 性能优化 使用缓存 - 减少数据库查询 分页 - 限制返回数据量 字段选择 - 只返回需要的字段 异步处理 - 长时间操作使用后台任务 数据库优化 - 索引、查询优化 API 设计检查清单 使用 RESTful 原则 一致的 URL 设计 适当的 HTTP 方法 正确的状态码 统一的错误格式 版本控制 身份验证和授权 速率限制 完整的文档 向后兼容性 安全措施 性能优化 总结 设计好的 API 需要考虑多个方面,包括可用性、安全性、性能和可维护性。遵循这些最佳实践能帮助你创建高质量的 API,提供更好的开发者体验。

2025-12-15 · 589 字 · MagicBude