Web开发最佳实践Skill best-practices

这个技能用于应用现代Web开发最佳实践,以提升网站安全性、浏览器兼容性和代码质量。包括HTTPS实施、内容安全策略(CSP)、安全头设置、依赖库漏洞检查、输入消毒、cookie安全等。适用于安全审计、代码现代化、代码质量审查、漏洞检查等场景。关键词:Web开发、最佳实践、安全、兼容性、代码质量、前端开发、HTTPS、CSP、输入消毒、漏洞审计。

前端开发 0 次安装 0 次浏览 更新于 3/21/2026

名称: 最佳实践 描述: 应用现代Web开发最佳实践,以提升安全性、兼容性和代码质量。适用于被要求“应用最佳实践”、“安全审计”、“代码现代化”、“代码质量审查”或“检查漏洞”的情况。 许可证: MIT 元数据: 作者: web-quality-skills 版本: “1.0”

最佳实践

基于Lighthouse最佳实践审计的现代Web开发标准。涵盖安全、浏览器兼容性和代码质量模式。

安全

处处使用HTTPS

强制使用HTTPS:

<!-- ❌ 混合内容 -->
<img src="http://example.com/image.jpg">
<script src="http://cdn.example.com/script.js"></script>

<!-- ✅ 仅使用HTTPS -->
<img src="https://example.com/image.jpg">
<script src="https://cdn.example.com/script.js"></script>

<!-- ✅ 协议相对(将使用页面的协议) -->
<img src="//example.com/image.jpg">

HSTS头部:

Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

内容安全策略(CSP)

<!-- 通过meta标签的基本CSP -->
<meta http-equiv="Content-Security-Policy" 
      content="default-src 'self'; 
               script-src 'self' https://trusted-cdn.com; 
               style-src 'self' 'unsafe-inline';
               img-src 'self' data: https:;
               connect-src 'self' https://api.example.com;">

<!-- 更好:HTTP头部 -->

CSP头部(推荐):

Content-Security-Policy: 
  default-src 'self';
  script-src 'self' 'nonce-abc123' https://trusted.com;
  style-src 'self' 'nonce-abc123';
  img-src 'self' data: https:;
  connect-src 'self' https://api.example.com;
  frame-ancestors 'self';
  base-uri 'self';
  form-action 'self';

使用nonce内联脚本:

<script nonce="abc123">
  // 这个内联脚本被允许
</script>

安全头部

# 防止点击劫持
X-Frame-Options: DENY

# 防止MIME类型嗅探
X-Content-Type-Options: nosniff

# 启用XSS过滤器(旧版浏览器)
X-XSS-Protection: 1; mode=block

# 控制引用信息
Referrer-Policy: strict-origin-when-cross-origin

# 权限策略(原Feature-Policy)
Permissions-Policy: geolocation=(), microphone=(), camera=()

无漏洞库

# 检查漏洞
npm audit
yarn audit

# 自动修复可能的问题
npm audit fix

# 检查特定包
npm ls lodash

保持依赖更新:

// package.json
{
  "scripts": {
    "audit": "npm audit --audit-level=moderate",
    "update": "npm update && npm audit fix"
  }
}

避免已知漏洞模式:

// ❌ 原型污染漏洞模式
Object.assign(target, userInput);
_.merge(target, userInput);

// ✅ 更安全的替代方案
const safeData = JSON.parse(JSON.stringify(userInput));

输入消毒

// ❌ XSS漏洞
element.innerHTML = userInput;
document.write(userInput);

// ✅ 安全的文本内容
element.textContent = userInput;

// ✅ 如果需要HTML,进行消毒
import DOMPurify from 'dompurify';
element.innerHTML = DOMPurify.sanitize(userInput);

安全cookies

// ❌ 不安全的cookie
document.cookie = "session=abc123";

// ✅ 安全cookie(服务器端)
Set-Cookie: session=abc123; Secure; HttpOnly; SameSite=Strict; Path=/

浏览器兼容性

文档类型声明

<!-- ❌ 缺失或无效的文档类型 -->
<HTML>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">

<!-- ✅ HTML5文档类型 -->
<!DOCTYPE html>
<html lang="zh">

字符编码

<!-- ❌ 缺失或过晚的字符集 -->
<html>
<head>
  <title>页面</title>
  <meta charset="UTF-8">
</head>

<!-- ✅ 字符集作为head的第一个元素 -->
<html>
<head>
  <meta charset="UTF-8">
  <title>页面</title>
</head>

视口meta标签

<!-- ❌ 缺失视口 -->
<head>
  <title>页面</title>
</head>

<!-- ✅ 响应式视口 -->
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>页面</title>
</head>

功能检测

// ❌ 浏览器检测(脆弱)
if (navigator.userAgent.includes('Chrome')) {
  // Chrome特定代码
}

// ✅ 功能检测
if ('IntersectionObserver' in window) {
  // 使用IntersectionObserver
} else {
  // 回退
}

// ✅ 在CSS中使用@supports
@supports (display: grid) {
  .container {
    display: grid;
  }
}

@supports not (display: grid) {
  .container {
    display: flex;
  }
}

填充库(当需要时)

<!-- 条件加载填充库 -->
<script>
  if (!('fetch' in window)) {
    document.write('<script src="/polyfills/fetch.js"><\/script>');
  }
</script>

<!-- 或使用polyfill.io -->
<script src="https://polyfill.io/v3/polyfill.min.js?features=fetch,IntersectionObserver"></script>

已弃用的API

避免这些

// ❌ document.write(阻塞解析)
document.write('<script src="..."></script>');

// ✅ 动态脚本加载
const script = document.createElement('script');
script.src = '...';
document.head.appendChild(script);

// ❌ 同步XHR(阻塞主线程)
const xhr = new XMLHttpRequest();
xhr.open('GET', url, false); // false = 同步

// ✅ 异步fetch
const response = await fetch(url);

// ❌ 应用程序缓存(已弃用)
<html manifest="cache.manifest">

// ✅ Service Workers
if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/sw.js');
}

事件监听器被动模式

// ❌ 非被动触摸/滚轮监听器(可能阻塞滚动)
element.addEventListener('touchstart', handler);
element.addEventListener('wheel', handler);

// ✅ 被动监听器(允许平滑滚动)
element.addEventListener('touchstart', handler, { passive: true });
element.addEventListener('wheel', handler, { passive: true });

// ✅ 如果需要preventDefault,明确指定
element.addEventListener('touchstart', handler, { passive: false });

控制台与错误

无控制台错误

// ❌ 生产环境中的错误
console.log('调试信息'); // 在生产环境中移除
throw new Error('未处理'); // 捕获所有错误

// ✅ 正确的错误处理
try {
  riskyOperation();
} catch (error) {
  // 记录到错误跟踪服务
  errorTracker.captureException(error);
  // 显示用户友好的消息
  showErrorMessage('出现问题,请重试。');
}

错误边界(React)

class ErrorBoundary extends React.Component {
  state = { hasError: false };
  
  static getDerivedStateFromError(error) {
    return { hasError: true };
  }
  
  componentDidCatch(error, info) {
    errorTracker.captureException(error, { extra: info });
  }
  
  render() {
    if (this.state.hasError) {
      return <FallbackUI />;
    }
    return this.props.children;
  }
}

// 使用
<ErrorBoundary>
  <App />
</ErrorBoundary>

全局错误处理器

// 捕获未处理的错误
window.addEventListener('error', (event) => {
  errorTracker.captureException(event.error);
});

// 捕获未处理的Promise拒绝
window.addEventListener('unhandledrejection', (event) => {
  errorTracker.captureException(event.reason);
});

源映射

生产配置

// ❌ 生产环境暴露源映射
// webpack.config.js
module.exports = {
  devtool: 'source-map', // 暴露源代码
};

// ✅ 隐藏源映射(上传到错误跟踪器)
module.exports = {
  devtool: 'hidden-source-map',
};

// ✅ 或生产环境无源映射
module.exports = {
  devtool: process.env.NODE_ENV === 'production' ? false : 'source-map',
};

性能最佳实践

避免阻塞模式

// ❌ 阻塞脚本
<script src="heavy-library.js"></script>

// ✅ 延迟脚本
<script defer src="heavy-library.js"></script>

// ❌ 阻塞CSS导入
@import url('other-styles.css');

// ✅ 链接标签(并行加载)
<link rel="stylesheet" href="styles.css">
<link rel="stylesheet" href="other-styles.css">

高效事件处理器

// ❌ 在每个元素上添加处理器
items.forEach(item => {
  item.addEventListener('click', handleClick);
});

// ✅ 事件委托
container.addEventListener('click', (e) => {
  if (e.target.matches('.item')) {
    handleClick(e);
  }
});

内存管理

// ❌ 内存泄漏(从未移除)
const handler = () => { /* ... */ };
window.addEventListener('resize', handler);

// ✅ 完成后清理
const handler = () => { /* ... */ };
window.addEventListener('resize', handler);

// 稍后,当组件卸载时:
window.removeEventListener('resize', handler);

// ✅ 使用AbortController
const controller = new AbortController();
window.addEventListener('resize', handler, { signal: controller.signal });

// 清理:
controller.abort();

代码质量

有效HTML

<!-- ❌ 无效HTML -->
<div id="header">
<div id="header"> <!-- 重复ID -->

<ul>
  <div>项目</div> <!-- 无效子元素 -->
</ul>

<a href="/"><button>点击</button></a> <!-- 无效嵌套 -->

<!-- ✅ 有效HTML -->
<header id="site-header">
</header>

<ul>
  <li>项目</li>
</ul>

<a href="/" class="button">点击</a>

语义HTML

<!-- ❌ 非语义 -->
<div class="header">
  <div class="nav">
    <div class="nav-item">首页</div>
  </div>
</div>
<div class="main">
  <div class="article">
    <div class="title">头条</div>
  </div>
</div>

<!-- ✅ 语义HTML5 -->
<header>
  <nav>
    <a href="/">首页</a>
  </nav>
</header>
<main>
  <article>
    <h1>头条</h1>
  </article>
</main>

图像宽高比

<!-- ❌ 失真图像 -->
<img src="photo.jpg" width="300" height="100">
<!-- 如果实际比例是4:3,这会挤压图像 -->

<!-- ✅ 保持宽高比 -->
<img src="photo.jpg" width="300" height="225">
<!-- 实际4:3尺寸 -->

<!-- ✅ 使用CSS object-fit灵活性 -->
<img src="photo.jpg" style="width: 300px; height: 200px; object-fit: cover;">

权限与隐私

正确请求权限

// ❌ 页面加载时请求(不良UX,常被拒绝)
navigator.geolocation.getCurrentPosition(success, error);

// ✅ 在上下文中,用户操作后请求
findNearbyButton.addEventListener('click', async () => {
  // 解释为什么需要
  if (await showPermissionExplanation()) {
    navigator.geolocation.getCurrentPosition(success, error);
  }
});

权限策略

<!-- 限制强大功能 -->
<meta http-equiv="Permissions-Policy" 
      content="geolocation=(), camera=(), microphone=()">

<!-- 或允许特定源 -->
<meta http-equiv="Permissions-Policy" 
      content="geolocation=(self 'https://maps.example.com')">

审计清单

安全(关键)

  • [ ] 启用HTTPS,无混合内容
  • [ ] 无漏洞依赖(npm audit
  • [ ] 配置CSP头部
  • [ ] 存在安全头部
  • [ ] 无暴露源映射

兼容性

  • [ ] 有效HTML5文档类型
  • [ ] 字符集在head中首先声明
  • [ ] 存在视口meta标签
  • [ ] 未使用已弃用的API
  • [ ] 滚动/触摸使用被动事件监听器

代码质量

  • [ ] 无控制台错误
  • [ ] 有效HTML(无重复ID)
  • [ ] 使用语义HTML元素
  • [ ] 正确的错误处理
  • [ ] 组件中的内存清理

UX

  • [ ] 无侵入性插页
  • [ ] 在上下文中请求权限
  • [ ] 清晰的错误消息
  • [ ] 合适的图像宽高比

工具

工具 用途
npm audit 依赖漏洞
SecurityHeaders.com 头部分析
W3C验证器 HTML验证
Lighthouse 最佳实践审计
Observatory 安全扫描

参考资料