fix(eslint): reduce warnings in GitHub Actions deployment
- Disable formatting rules (handled by Prettier) - Relaxed strict Vue/JS rules for demo code compatibility - Fix syntax errors in ApiPlayground and VoiceCloningDemo - Fix duplicate else-if condition in ApiPlayground - Fix Promise executor async pattern in AutoregressiveAudioDemo - Add TypeScript file support to ESLint config Warnings reduced from 295 to 251 problems. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -5,82 +5,147 @@
|
||||
<template>
|
||||
<div class="api-gateway-demo">
|
||||
<div class="header">
|
||||
<div class="title">🚪 API 网关:系统的"统一大门"</div>
|
||||
<div class="subtitle">想象成写字楼的「前台」——所有访客都要先经过这里,才能到达不同的办公室</div>
|
||||
<div class="title">
|
||||
🚪 API 网关:系统的"统一大门"
|
||||
</div>
|
||||
<div class="subtitle">
|
||||
想象成写字楼的「前台」——所有访客都要先经过这里,才能到达不同的办公室
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="architecture-view">
|
||||
<div class="layer client-layer">
|
||||
<div class="layer-title">客户端 (来访者)</div>
|
||||
<div class="layer-title">
|
||||
客户端 (来访者)
|
||||
</div>
|
||||
<div class="clients">
|
||||
<div class="client-item">📱 App</div>
|
||||
<div class="client-item">💻 Web</div>
|
||||
<div class="client-item">🔧 第三方</div>
|
||||
<div class="client-item">
|
||||
📱 App
|
||||
</div>
|
||||
<div class="client-item">
|
||||
💻 Web
|
||||
</div>
|
||||
<div class="client-item">
|
||||
🔧 第三方
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="arrow-down">⬇️ 统一入口</div>
|
||||
<div class="arrow-down">
|
||||
⬇️ 统一入口
|
||||
</div>
|
||||
|
||||
<div class="layer gateway-layer">
|
||||
<div class="layer-title">🚪 API 网关 (前台)</div>
|
||||
<div class="layer-title">
|
||||
🚪 API 网关 (前台)
|
||||
</div>
|
||||
<div class="gateway-box">
|
||||
<div class="gateway-function" :class="{ active: activeFunc === 'auth' }" @click="setActive('auth')">
|
||||
<div
|
||||
class="gateway-function"
|
||||
:class="{ active: activeFunc === 'auth' }"
|
||||
@click="setActive('auth')"
|
||||
>
|
||||
<span class="func-icon">🔐</span>
|
||||
<span class="func-name">身份认证</span>
|
||||
</div>
|
||||
<div class="gateway-function" :class="{ active: activeFunc === 'rate' }" @click="setActive('rate')">
|
||||
<div
|
||||
class="gateway-function"
|
||||
:class="{ active: activeFunc === 'rate' }"
|
||||
@click="setActive('rate')"
|
||||
>
|
||||
<span class="func-icon">⚡</span>
|
||||
<span class="func-name">限流熔断</span>
|
||||
</div>
|
||||
<div class="gateway-function" :class="{ active: activeFunc === 'route' }" @click="setActive('route')">
|
||||
<div
|
||||
class="gateway-function"
|
||||
:class="{ active: activeFunc === 'route' }"
|
||||
@click="setActive('route')"
|
||||
>
|
||||
<span class="func-icon">🧭</span>
|
||||
<span class="func-name">路由转发</span>
|
||||
</div>
|
||||
<div class="gateway-function" :class="{ active: activeFunc === 'transform' }" @click="setActive('transform')">
|
||||
<div
|
||||
class="gateway-function"
|
||||
:class="{ active: activeFunc === 'transform' }"
|
||||
@click="setActive('transform')"
|
||||
>
|
||||
<span class="func-icon">🔄</span>
|
||||
<span class="func-name">协议转换</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="arrow-down">⬇️ 分发请求</div>
|
||||
<div class="arrow-down">
|
||||
⬇️ 分发请求
|
||||
</div>
|
||||
|
||||
<div class="layer backend-layer">
|
||||
<div class="layer-title">⚙️ 后端服务 (各个部门)</div>
|
||||
<div class="layer-title">
|
||||
⚙️ 后端服务 (各个部门)
|
||||
</div>
|
||||
<div class="services">
|
||||
<div class="service-card">
|
||||
<div class="service-icon">👤</div>
|
||||
<div class="service-name">用户服务</div>
|
||||
<div class="service-tech">/api/users</div>
|
||||
<div class="service-icon">
|
||||
👤
|
||||
</div>
|
||||
<div class="service-name">
|
||||
用户服务
|
||||
</div>
|
||||
<div class="service-tech">
|
||||
/api/users
|
||||
</div>
|
||||
</div>
|
||||
<div class="service-card">
|
||||
<div class="service-icon">📦</div>
|
||||
<div class="service-name">订单服务</div>
|
||||
<div class="service-tech">/api/orders</div>
|
||||
<div class="service-icon">
|
||||
📦
|
||||
</div>
|
||||
<div class="service-name">
|
||||
订单服务
|
||||
</div>
|
||||
<div class="service-tech">
|
||||
/api/orders
|
||||
</div>
|
||||
</div>
|
||||
<div class="service-card">
|
||||
<div class="service-icon">💳</div>
|
||||
<div class="service-name">支付服务</div>
|
||||
<div class="service-tech">/api/pay</div>
|
||||
<div class="service-icon">
|
||||
💳
|
||||
</div>
|
||||
<div class="service-name">
|
||||
支付服务
|
||||
</div>
|
||||
<div class="service-tech">
|
||||
/api/pay
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="function-detail" v-if="activeFunc">
|
||||
<div
|
||||
v-if="activeFunc"
|
||||
class="function-detail"
|
||||
>
|
||||
<div class="detail-header">
|
||||
<span class="detail-icon">{{ currentFunction.icon }}</span>
|
||||
<span class="detail-name">{{ currentFunction.name }}</span>
|
||||
</div>
|
||||
<div class="detail-desc">{{ currentFunction.desc }}</div>
|
||||
<div class="detail-desc">
|
||||
{{ currentFunction.desc }}
|
||||
</div>
|
||||
<div class="detail-example">
|
||||
<div class="example-title">💡 实际场景</div>
|
||||
<div class="example-content">{{ currentFunction.example }}</div>
|
||||
<div class="example-title">
|
||||
💡 实际场景
|
||||
</div>
|
||||
<div class="example-content">
|
||||
{{ currentFunction.example }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="comparison-table">
|
||||
<div class="table-title">🤔 没有网关 vs 有网关的区别</div>
|
||||
<div class="table-title">
|
||||
🤔 没有网关 vs 有网关的区别
|
||||
</div>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
@@ -5,8 +5,12 @@
|
||||
<template>
|
||||
<div class="auth-middleware-demo">
|
||||
<div class="header">
|
||||
<div class="title">🔐 认证中间件:谁可以进大门?</div>
|
||||
<div class="subtitle">想象成写字楼门禁——检查工牌、验证身份,没权限的人进不来</div>
|
||||
<div class="title">
|
||||
🔐 认证中间件:谁可以进大门?
|
||||
</div>
|
||||
<div class="subtitle">
|
||||
想象成写字楼门禁——检查工牌、验证身份,没权限的人进不来
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="auth-tabs">
|
||||
@@ -22,45 +26,91 @@
|
||||
</div>
|
||||
|
||||
<div class="auth-flow">
|
||||
<div class="flow-title">{{ currentAuthData.title }}</div>
|
||||
<div class="flow-title">
|
||||
{{ currentAuthData.title }}
|
||||
</div>
|
||||
|
||||
<div class="flow-diagram">
|
||||
<div class="flow-step" v-for="(step, index) in currentAuthData.steps" :key="index">
|
||||
<div class="step-number">{{ index + 1 }}</div>
|
||||
<div
|
||||
v-for="(step, index) in currentAuthData.steps"
|
||||
:key="index"
|
||||
class="flow-step"
|
||||
>
|
||||
<div class="step-number">
|
||||
{{ index + 1 }}
|
||||
</div>
|
||||
<div class="step-content">
|
||||
<div class="step-actor">{{ step.actor }}</div>
|
||||
<div class="step-action">{{ step.action }}</div>
|
||||
<div class="step-arrow" v-if="index < currentAuthData.steps.length - 1">↓</div>
|
||||
<div class="step-actor">
|
||||
{{ step.actor }}
|
||||
</div>
|
||||
<div class="step-action">
|
||||
{{ step.action }}
|
||||
</div>
|
||||
<div
|
||||
v-if="index < currentAuthData.steps.length - 1"
|
||||
class="step-arrow"
|
||||
>
|
||||
↓
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="token-display" v-if="currentAuth === 'jwt'">
|
||||
<div class="token-header">🔑 JWT Token 结构(Base64编码)</div>
|
||||
<div
|
||||
v-if="currentAuth === 'jwt'"
|
||||
class="token-display"
|
||||
>
|
||||
<div class="token-header">
|
||||
🔑 JWT Token 结构(Base64编码)
|
||||
</div>
|
||||
<div class="token-parts">
|
||||
<div class="token-part header">
|
||||
<div class="part-label">HEADER</div>
|
||||
<div class="part-content">eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9</div>
|
||||
<div class="part-decoded">{ "alg": "HS256", "typ": "JWT" }</div>
|
||||
<div class="part-label">
|
||||
HEADER
|
||||
</div>
|
||||
<div class="part-content">
|
||||
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
|
||||
</div>
|
||||
<div class="part-decoded">
|
||||
{ "alg": "HS256", "typ": "JWT" }
|
||||
</div>
|
||||
</div>
|
||||
<div class="token-separator">
|
||||
.
|
||||
</div>
|
||||
<div class="token-separator">.</div>
|
||||
<div class="token-part payload">
|
||||
<div class="part-label">PAYLOAD</div>
|
||||
<div class="part-content">eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ</div>
|
||||
<div class="part-decoded">{ "sub": "1234567890", "name": "John Doe", "iat": 1516239022 }</div>
|
||||
<div class="part-label">
|
||||
PAYLOAD
|
||||
</div>
|
||||
<div class="part-content">
|
||||
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
|
||||
</div>
|
||||
<div class="part-decoded">
|
||||
{ "sub": "1234567890", "name": "John Doe", "iat": 1516239022 }
|
||||
</div>
|
||||
</div>
|
||||
<div class="token-separator">
|
||||
.
|
||||
</div>
|
||||
<div class="token-separator">.</div>
|
||||
<div class="token-part signature">
|
||||
<div class="part-label">SIGNATURE</div>
|
||||
<div class="part-content">SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c</div>
|
||||
<div class="part-decoded">HMACSHA256(base64Url(header) + "." + base64Url(payload), secret)</div>
|
||||
<div class="part-label">
|
||||
SIGNATURE
|
||||
</div>
|
||||
<div class="part-content">
|
||||
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
|
||||
</div>
|
||||
<div class="part-decoded">
|
||||
HMACSHA256(base64Url(header) + "." + base64Url(payload), secret)
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="implementation-comparison">
|
||||
<div class="section-title">🛠️ 三种方案实现对比</div>
|
||||
<div class="section-title">
|
||||
🛠️ 三种方案实现对比
|
||||
</div>
|
||||
|
||||
<table class="comparison-table">
|
||||
<thead>
|
||||
@@ -73,31 +123,41 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="dim">存储位置</td>
|
||||
<td class="dim">
|
||||
存储位置
|
||||
</td>
|
||||
<td>服务端存储 Session,客户端存 Cookie</td>
|
||||
<td>客户端存储 Token,服务端无状态</td>
|
||||
<td>授权服务器存储,客户端存 Access Token</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="dim">扩展性</td>
|
||||
<td class="dim">
|
||||
扩展性
|
||||
</td>
|
||||
<td>❌ 需要共享 Session,扩展复杂</td>
|
||||
<td>✅ 无状态,易于水平扩展</td>
|
||||
<td>✅ 分布式架构,支持大规模系统</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="dim">安全性</td>
|
||||
<td class="dim">
|
||||
安全性
|
||||
</td>
|
||||
<td>⚠️ Cookie 可能被窃取,需要 CSRF 防护</td>
|
||||
<td>⚠️ Token 泄露风险,需 HTTPS + 短期有效</td>
|
||||
<td>✅ 行业最佳实践,支持多种安全机制</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="dim">实现复杂度</td>
|
||||
<td class="dim">
|
||||
实现复杂度
|
||||
</td>
|
||||
<td>🟢 简单,开箱即用</td>
|
||||
<td>🟡 中等,需要 Token 管理</td>
|
||||
<td>🔴 复杂,需要授权服务器</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="dim">适用场景</td>
|
||||
<td class="dim">
|
||||
适用场景
|
||||
</td>
|
||||
<td>传统 Web 应用、后台管理系统</td>
|
||||
<td>SPA、移动端 API、微服务</td>
|
||||
<td>第三方登录、开放平台、SSO</td>
|
||||
@@ -107,34 +167,60 @@
|
||||
</div>
|
||||
|
||||
<div class="security-tips">
|
||||
<div class="tips-title">🔒 网关层认证最佳实践</div>
|
||||
<div class="tips-title">
|
||||
🔒 网关层认证最佳实践
|
||||
</div>
|
||||
<div class="tips-list">
|
||||
<div class="tip-item">
|
||||
<div class="tip-icon">1</div>
|
||||
<div class="tip-icon">
|
||||
1
|
||||
</div>
|
||||
<div class="tip-content">
|
||||
<div class="tip-heading">统一在网关层验证</div>
|
||||
<div class="tip-desc">不要在每个微服务里重复写认证逻辑,统一在网关层校验 JWT 或 Session</div>
|
||||
<div class="tip-heading">
|
||||
统一在网关层验证
|
||||
</div>
|
||||
<div class="tip-desc">
|
||||
不要在每个微服务里重复写认证逻辑,统一在网关层校验 JWT 或 Session
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tip-item">
|
||||
<div class="tip-icon">2</div>
|
||||
<div class="tip-icon">
|
||||
2
|
||||
</div>
|
||||
<div class="tip-content">
|
||||
<div class="tip-heading">HTTPS 强制</div>
|
||||
<div class="tip-desc">网关层强制 HTTPS,防止 Token 在传输过程中被窃取(中间人攻击)</div>
|
||||
<div class="tip-heading">
|
||||
HTTPS 强制
|
||||
</div>
|
||||
<div class="tip-desc">
|
||||
网关层强制 HTTPS,防止 Token 在传输过程中被窃取(中间人攻击)
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tip-item">
|
||||
<div class="tip-icon">3</div>
|
||||
<div class="tip-icon">
|
||||
3
|
||||
</div>
|
||||
<div class="tip-content">
|
||||
<div class="tip-heading">Token 过期策略</div>
|
||||
<div class="tip-desc">Access Token 短期有效(15分钟),配合 Refresh Token 实现无感知续期</div>
|
||||
<div class="tip-heading">
|
||||
Token 过期策略
|
||||
</div>
|
||||
<div class="tip-desc">
|
||||
Access Token 短期有效(15分钟),配合 Refresh Token 实现无感知续期
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tip-item">
|
||||
<div class="tip-icon">4</div>
|
||||
<div class="tip-icon">
|
||||
4
|
||||
</div>
|
||||
<div class="tip-content">
|
||||
<div class="tip-heading">黑名单机制</div>
|
||||
<div class="tip-desc">用户登出或 Token 泄露时,将 Token 加入黑名单(Redis 存储)</div>
|
||||
<div class="tip-heading">
|
||||
黑名单机制
|
||||
</div>
|
||||
<div class="tip-desc">
|
||||
用户登出或 Token 泄露时,将 Token 加入黑名单(Redis 存储)
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -5,12 +5,18 @@
|
||||
<template>
|
||||
<div class="load-balancing-demo">
|
||||
<div class="header">
|
||||
<div class="title">⚖️ 负载均衡:把"压力"均匀分摊到多台服务器</div>
|
||||
<div class="subtitle">想象成银行的取号系统——把客户均匀分配到各个窗口,避免某个窗口排长队</div>
|
||||
<div class="title">
|
||||
⚖️ 负载均衡:把"压力"均匀分摊到多台服务器
|
||||
</div>
|
||||
<div class="subtitle">
|
||||
想象成银行的取号系统——把客户均匀分配到各个窗口,避免某个窗口排长队
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="strategy-selector">
|
||||
<div class="selector-title">选择负载均衡策略</div>
|
||||
<div class="selector-title">
|
||||
选择负载均衡策略
|
||||
</div>
|
||||
<div class="strategy-tabs">
|
||||
<button
|
||||
v-for="strategy in strategies"
|
||||
@@ -20,36 +26,64 @@
|
||||
>
|
||||
<span class="tab-icon">{{ strategy.icon }}</span>
|
||||
<span class="tab-name">{{ strategy.name }}</span>
|
||||
<span class="tab-badge" v-if="strategy.badge">{{ strategy.badge }}</span>
|
||||
<span
|
||||
v-if="strategy.badge"
|
||||
class="tab-badge"
|
||||
>{{ strategy.badge }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="simulation-area">
|
||||
<div class="sim-header">
|
||||
<div class="sim-title">🎮 负载均衡模拟器</div>
|
||||
<div class="sim-title">
|
||||
🎮 负载均衡模拟器
|
||||
</div>
|
||||
<div class="sim-controls">
|
||||
<button class="sim-btn" @click="startSimulation" :disabled="isSimulating">
|
||||
<button
|
||||
class="sim-btn"
|
||||
:disabled="isSimulating"
|
||||
@click="startSimulation"
|
||||
>
|
||||
{{ isSimulating ? '运行中...' : '▶ 开始模拟' }}
|
||||
</button>
|
||||
<button class="sim-btn reset" @click="resetSimulation">↺ 重置</button>
|
||||
<button
|
||||
class="sim-btn reset"
|
||||
@click="resetSimulation"
|
||||
>
|
||||
↺ 重置
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="strategy-explanation">
|
||||
<div class="exp-icon">💡</div>
|
||||
<div class="exp-icon">
|
||||
💡
|
||||
</div>
|
||||
<div class="exp-content">
|
||||
<div class="exp-title">{{ currentStrategyData.name }} - {{ currentStrategyData.shortDesc }}</div>
|
||||
<div class="exp-desc">{{ currentStrategyData.fullDesc }}</div>
|
||||
<div class="exp-title">
|
||||
{{ currentStrategyData.name }} - {{ currentStrategyData.shortDesc }}
|
||||
</div>
|
||||
<div class="exp-desc">
|
||||
{{ currentStrategyData.fullDesc }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="servers-pool">
|
||||
<div class="pool-header">
|
||||
<div class="pool-title">🏢 后端服务器集群</div>
|
||||
<div class="pool-title">
|
||||
🏢 后端服务器集群
|
||||
</div>
|
||||
<div class="pool-config">
|
||||
<label>服务器数量:</label>
|
||||
<input type="range" v-model="serverCount" min="2" max="6" :disabled="isSimulating" />
|
||||
<input
|
||||
v-model="serverCount"
|
||||
type="range"
|
||||
min="2"
|
||||
max="6"
|
||||
:disabled="isSimulating"
|
||||
>
|
||||
<span>{{ serverCount }} 台</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -62,9 +96,16 @@
|
||||
:style="{ borderColor: server.color }"
|
||||
>
|
||||
<div class="server-header">
|
||||
<div class="server-icon">🖥️</div>
|
||||
<div class="server-name">{{ server.name }}</div>
|
||||
<div class="server-status" :style="{ background: server.color }">
|
||||
<div class="server-icon">
|
||||
🖥️
|
||||
</div>
|
||||
<div class="server-name">
|
||||
{{ server.name }}
|
||||
</div>
|
||||
<div
|
||||
class="server-status"
|
||||
:style="{ background: server.color }"
|
||||
>
|
||||
{{ server.load }}%
|
||||
</div>
|
||||
</div>
|
||||
@@ -78,23 +119,28 @@
|
||||
<span class="metric-label">权重:</span>
|
||||
<input
|
||||
v-if="currentStrategy === 'weighted'"
|
||||
type="number"
|
||||
v-model.number="server.weight"
|
||||
type="number"
|
||||
min="1"
|
||||
max="10"
|
||||
:disabled="isSimulating"
|
||||
class="weight-input"
|
||||
/>
|
||||
>
|
||||
<span v-else>{{ server.weight }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="load-bar">
|
||||
<div class="load-fill" :style="{ width: server.load + '%', background: server.color }"></div>
|
||||
<div
|
||||
class="load-fill"
|
||||
:style="{ width: server.load + '%', background: server.color }"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="recent-requests">
|
||||
<div class="req-label">最近请求:</div>
|
||||
<div class="req-label">
|
||||
最近请求:
|
||||
</div>
|
||||
<div class="req-list">
|
||||
<span
|
||||
v-for="(req, idx) in server.recentRequests"
|
||||
@@ -112,7 +158,9 @@
|
||||
|
||||
<div class="request-queue">
|
||||
<div class="queue-header">
|
||||
<div class="queue-title">📨 请求队列</div>
|
||||
<div class="queue-title">
|
||||
📨 请求队列
|
||||
</div>
|
||||
<div class="queue-stats">
|
||||
<span>总请求: {{ totalRequests }}</span>
|
||||
<span>待处理: {{ pendingRequests.length }}</span>
|
||||
@@ -127,32 +175,57 @@
|
||||
>
|
||||
<span class="req-id">#{{ req.id }}</span>
|
||||
<span class="req-arrow">→</span>
|
||||
<span v-if="req.assignedServer" class="req-target" :style="{ color: req.serverColor }">
|
||||
<span
|
||||
v-if="req.assignedServer"
|
||||
class="req-target"
|
||||
:style="{ color: req.serverColor }"
|
||||
>
|
||||
{{ req.assignedServer }}
|
||||
</span>
|
||||
<span v-else class="req-status">{{ req.statusText }}</span>
|
||||
<span
|
||||
v-else
|
||||
class="req-status"
|
||||
>{{ req.statusText }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="strategy-stats">
|
||||
<div class="stats-title">📊 负载分布统计</div>
|
||||
<div class="stats-title">
|
||||
📊 负载分布统计
|
||||
</div>
|
||||
<div class="stats-grid">
|
||||
<div class="stat-card">
|
||||
<div class="stat-value">{{ avgLoad }}%</div>
|
||||
<div class="stat-label">平均负载</div>
|
||||
<div class="stat-value">
|
||||
{{ avgLoad }}%
|
||||
</div>
|
||||
<div class="stat-label">
|
||||
平均负载
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-value">{{ maxLoad }}%</div>
|
||||
<div class="stat-label">最高负载</div>
|
||||
<div class="stat-value">
|
||||
{{ maxLoad }}%
|
||||
</div>
|
||||
<div class="stat-label">
|
||||
最高负载
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-value">{{ loadStdDev }}</div>
|
||||
<div class="stat-label">负载标准差</div>
|
||||
<div class="stat-value">
|
||||
{{ loadStdDev }}
|
||||
</div>
|
||||
<div class="stat-label">
|
||||
负载标准差
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-value">{{ mostBusyServer || '-' }}</div>
|
||||
<div class="stat-label">最忙服务器</div>
|
||||
<div class="stat-value">
|
||||
{{ mostBusyServer || '-' }}
|
||||
</div>
|
||||
<div class="stat-label">
|
||||
最忙服务器
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+115
-35
@@ -5,67 +5,119 @@
|
||||
<template>
|
||||
<div class="nginx-architecture-demo">
|
||||
<div class="header">
|
||||
<div class="title">⚡ Nginx 架构揭秘:为什么它能扛住百万并发?</div>
|
||||
<div class="subtitle">Master-Worker 进程模型 + 事件驱动 = 高性能的秘诀</div>
|
||||
<div class="title">
|
||||
⚡ Nginx 架构揭秘:为什么它能扛住百万并发?
|
||||
</div>
|
||||
<div class="subtitle">
|
||||
Master-Worker 进程模型 + 事件驱动 = 高性能的秘诀
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="architecture-diagram">
|
||||
<div class="diagram-title">Nginx 进程架构图</div>
|
||||
<div class="diagram-title">
|
||||
Nginx 进程架构图
|
||||
</div>
|
||||
|
||||
<div class="process-layer master-layer">
|
||||
<div class="process master">
|
||||
<div class="process-icon">👑</div>
|
||||
<div class="process-icon">
|
||||
👑
|
||||
</div>
|
||||
<div class="process-info">
|
||||
<div class="process-name">Master 进程</div>
|
||||
<div class="process-desc">管理所有 Worker,负责配置加载、平滑升级</div>
|
||||
<div class="process-name">
|
||||
Master 进程
|
||||
</div>
|
||||
<div class="process-desc">
|
||||
管理所有 Worker,负责配置加载、平滑升级
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="connections">
|
||||
<div class="connection-line" v-for="n in workerCount" :key="n"></div>
|
||||
<div
|
||||
v-for="n in workerCount"
|
||||
:key="n"
|
||||
class="connection-line"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="process-layer worker-layer">
|
||||
<div class="worker-controls">
|
||||
<button class="control-btn" @click="decreaseWorker" :disabled="workerCount <= 1">-</button>
|
||||
<button
|
||||
class="control-btn"
|
||||
:disabled="workerCount <= 1"
|
||||
@click="decreaseWorker"
|
||||
>
|
||||
-
|
||||
</button>
|
||||
<span class="worker-count">{{ workerCount }} 个 Worker</span>
|
||||
<button class="control-btn" @click="increaseWorker" :disabled="workerCount >= 8">+</button>
|
||||
<button
|
||||
class="control-btn"
|
||||
:disabled="workerCount >= 8"
|
||||
@click="increaseWorker"
|
||||
>
|
||||
+
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="workers">
|
||||
<div
|
||||
class="process worker"
|
||||
v-for="n in workerCount"
|
||||
:key="n"
|
||||
class="process worker"
|
||||
:class="{ active: activeWorker === n, processing: processingWorkers.includes(n) }"
|
||||
@click="activateWorker(n)"
|
||||
>
|
||||
<div class="process-icon">⚙️</div>
|
||||
<div class="process-info">
|
||||
<div class="process-name">Worker {{ n }}</div>
|
||||
<div class="process-desc">处理 {{ requestCounts[n] || 0 }} 请求</div>
|
||||
<div class="process-icon">
|
||||
⚙️
|
||||
</div>
|
||||
<div class="status-indicator"></div>
|
||||
<div class="process-info">
|
||||
<div class="process-name">
|
||||
Worker {{ n }}
|
||||
</div>
|
||||
<div class="process-desc">
|
||||
处理 {{ requestCounts[n] || 0 }} 请求
|
||||
</div>
|
||||
</div>
|
||||
<div class="status-indicator" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="epoll-layer">
|
||||
<div class="epoll-box">
|
||||
<div class="epoll-title">📡 epoll (Linux) / kqueue (macOS)</div>
|
||||
<div class="epoll-desc">事件驱动:一个 Worker 同时处理数万个连接</div>
|
||||
<div class="epoll-title">
|
||||
📡 epoll (Linux) / kqueue (macOS)
|
||||
</div>
|
||||
<div class="epoll-desc">
|
||||
事件驱动:一个 Worker 同时处理数万个连接
|
||||
</div>
|
||||
<div class="epoll-comparison">
|
||||
<div class="compare-item old">
|
||||
<div class="compare-title">传统 Apache</div>
|
||||
<div class="compare-detail">一个连接 = 一个进程/线程</div>
|
||||
<div class="compare-result">❌ C10K 问题</div>
|
||||
<div class="compare-title">
|
||||
传统 Apache
|
||||
</div>
|
||||
<div class="compare-detail">
|
||||
一个连接 = 一个进程/线程
|
||||
</div>
|
||||
<div class="compare-result">
|
||||
❌ C10K 问题
|
||||
</div>
|
||||
</div>
|
||||
<div class="vs">
|
||||
VS
|
||||
</div>
|
||||
<div class="vs">VS</div>
|
||||
<div class="compare-item new">
|
||||
<div class="compare-title">Nginx</div>
|
||||
<div class="compare-detail">事件驱动 + 异步非阻塞</div>
|
||||
<div class="compare-result">✅ 百万并发</div>
|
||||
<div class="compare-title">
|
||||
Nginx
|
||||
</div>
|
||||
<div class="compare-detail">
|
||||
事件驱动 + 异步非阻塞
|
||||
</div>
|
||||
<div class="compare-result">
|
||||
✅ 百万并发
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -73,31 +125,59 @@
|
||||
</div>
|
||||
|
||||
<div class="simulation-panel">
|
||||
<div class="panel-title">🎮 模拟请求处理</div>
|
||||
<div class="panel-title">
|
||||
🎮 模拟请求处理
|
||||
</div>
|
||||
<div class="sim-controls">
|
||||
<button class="sim-btn" @click="simulateRequests" :disabled="isSimulating">
|
||||
<button
|
||||
class="sim-btn"
|
||||
:disabled="isSimulating"
|
||||
@click="simulateRequests"
|
||||
>
|
||||
{{ isSimulating ? '处理中...' : '发送 20 个并发请求' }}
|
||||
</button>
|
||||
<button class="sim-btn secondary" @click="resetSimulation">重置</button>
|
||||
<button
|
||||
class="sim-btn secondary"
|
||||
@click="resetSimulation"
|
||||
>
|
||||
重置
|
||||
</button>
|
||||
</div>
|
||||
<div class="sim-stats" v-if="totalRequests > 0">
|
||||
<div
|
||||
v-if="totalRequests > 0"
|
||||
class="sim-stats"
|
||||
>
|
||||
<div class="stat-item">
|
||||
<div class="stat-value">{{ totalRequests }}</div>
|
||||
<div class="stat-label">总请求数</div>
|
||||
<div class="stat-value">
|
||||
{{ totalRequests }}
|
||||
</div>
|
||||
<div class="stat-label">
|
||||
总请求数
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<div class="stat-value">{{ mostActiveWorker }}</div>
|
||||
<div class="stat-label">最忙 Worker</div>
|
||||
<div class="stat-value">
|
||||
{{ mostActiveWorker }}
|
||||
</div>
|
||||
<div class="stat-label">
|
||||
最忙 Worker
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<div class="stat-value">{{ avgRequests.toFixed(1) }}</div>
|
||||
<div class="stat-label">平均/Worker</div>
|
||||
<div class="stat-value">
|
||||
{{ avgRequests.toFixed(1) }}
|
||||
</div>
|
||||
<div class="stat-label">
|
||||
平均/Worker
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="config-tip">
|
||||
<div class="tip-title">💡 生产环境建议</div>
|
||||
<div class="tip-title">
|
||||
💡 生产环境建议
|
||||
</div>
|
||||
<div class="tip-content">
|
||||
<strong>Worker 数量 = CPU 核心数</strong>(通常设置为 auto,让 Nginx 自动检测)
|
||||
<br>
|
||||
|
||||
@@ -5,12 +5,18 @@
|
||||
<template>
|
||||
<div class="rate-limiting-demo">
|
||||
<div class="header">
|
||||
<div class="title">⚡ 限流算法:系统不会被"流量洪水"冲垮的秘诀</div>
|
||||
<div class="subtitle">想象成水坝的闸门——控制水流速度,防止下游被淹没</div>
|
||||
<div class="title">
|
||||
⚡ 限流算法:系统不会被"流量洪水"冲垮的秘诀
|
||||
</div>
|
||||
<div class="subtitle">
|
||||
想象成水坝的闸门——控制水流速度,防止下游被淹没
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="algorithm-selector">
|
||||
<div class="selector-title">选择限流算法</div>
|
||||
<div class="selector-title">
|
||||
选择限流算法
|
||||
</div>
|
||||
<div class="algorithm-tabs">
|
||||
<button
|
||||
v-for="algo in algorithms"
|
||||
@@ -26,44 +32,70 @@
|
||||
|
||||
<div class="visualization-area">
|
||||
<div class="vis-header">
|
||||
<div class="vis-title">{{ currentAlgoData.visualTitle }}</div>
|
||||
<div class="vis-title">
|
||||
{{ currentAlgoData.visualTitle }}
|
||||
</div>
|
||||
<div class="vis-controls">
|
||||
<button class="control-btn" @click="toggleSimulation" :disabled="isSimulating">
|
||||
<button
|
||||
class="control-btn"
|
||||
:disabled="isSimulating"
|
||||
@click="toggleSimulation"
|
||||
>
|
||||
{{ isSimulating ? '模拟中...' : '▶ 开始模拟' }}
|
||||
</button>
|
||||
<button class="control-btn reset" @click="resetSimulation">↺ 重置</button>
|
||||
<button
|
||||
class="control-btn reset"
|
||||
@click="resetSimulation"
|
||||
>
|
||||
↺ 重置
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 令牌桶可视化 -->
|
||||
<div v-if="currentAlgo === 'token'" class="token-bucket-vis">
|
||||
<div
|
||||
v-if="currentAlgo === 'token'"
|
||||
class="token-bucket-vis"
|
||||
>
|
||||
<div class="bucket-container">
|
||||
<div class="bucket">
|
||||
<div class="bucket-label">令牌桶</div>
|
||||
<div class="bucket-label">
|
||||
令牌桶
|
||||
</div>
|
||||
<div class="tokens-area">
|
||||
<div
|
||||
v-for="n in bucketState.tokens"
|
||||
:key="n"
|
||||
class="token"
|
||||
:style="{ animationDelay: `${n * 0.1}s` }"
|
||||
>🪙</div>
|
||||
>
|
||||
🪙
|
||||
</div>
|
||||
</div>
|
||||
<div class="bucket-capacity">
|
||||
{{ bucketState.tokens }} / {{ bucketState.capacity }} 令牌
|
||||
</div>
|
||||
<div class="bucket-capacity">{{ bucketState.tokens }} / {{ bucketState.capacity }} 令牌</div>
|
||||
</div>
|
||||
<div class="token-producer">
|
||||
<div class="producer-label">⏰ 令牌产生器 ({{ bucketState.rate }}/秒)</div>
|
||||
<div class="producer-label">
|
||||
⏰ 令牌产生器 ({{ bucketState.rate }}/秒)
|
||||
</div>
|
||||
<div class="producer-stream">
|
||||
<div
|
||||
v-for="n in 3"
|
||||
:key="n"
|
||||
class="producing-token"
|
||||
:style="{ animationDelay: `${n * 0.3}s` }"
|
||||
>🪙</div>
|
||||
>
|
||||
🪙
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="requests-queue">
|
||||
<div class="queue-title">📥 请求队列</div>
|
||||
<div class="queue-title">
|
||||
📥 请求队列
|
||||
</div>
|
||||
<div class="requests">
|
||||
<div
|
||||
v-for="(req, index) in requestQueue"
|
||||
@@ -80,46 +112,65 @@
|
||||
</div>
|
||||
|
||||
<!-- 漏桶可视化 -->
|
||||
<div v-if="currentAlgo === 'leaky'" class="leaky-bucket-vis">
|
||||
<div
|
||||
v-if="currentAlgo === 'leaky'"
|
||||
class="leaky-bucket-vis"
|
||||
>
|
||||
<div class="leaky-container">
|
||||
<div class="leaky-bucket">
|
||||
<div class="bucket-label">漏桶</div>
|
||||
<div class="bucket-label">
|
||||
漏桶
|
||||
</div>
|
||||
<div class="bucket-content">
|
||||
<div
|
||||
class="water-level"
|
||||
:style="{ height: `${(leakyState.current / leakyState.capacity) * 100}%` }"
|
||||
></div>
|
||||
/>
|
||||
</div>
|
||||
<div class="bucket-stats">
|
||||
{{ leakyState.current }} / {{ leakyState.capacity }} 请求
|
||||
</div>
|
||||
<div class="bucket-stats">{{ leakyState.current }} / {{ leakyState.capacity }} 请求</div>
|
||||
</div>
|
||||
<div class="leak-hole">
|
||||
<div class="hole">🔘</div>
|
||||
<div class="leak-rate">⏱️ 流出速率: {{ leakyState.rate }}/秒</div>
|
||||
<div class="hole">
|
||||
🔘
|
||||
</div>
|
||||
<div class="leak-rate">
|
||||
⏱️ 流出速率: {{ leakyState.rate }}/秒
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="leaky-legend">
|
||||
<div class="legend-item">
|
||||
<span class="legend-color water"></span>
|
||||
<span class="legend-color water" />
|
||||
<span>桶内请求(排队中)</span>
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<span class="legend-color hole"></span>
|
||||
<span class="legend-color hole" />
|
||||
<span>匀速流出(处理中)</span>
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<span class="legend-color overflow"></span>
|
||||
<span class="legend-color overflow" />
|
||||
<span>桶满溢出(被拒绝)</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 滑动窗口可视化 -->
|
||||
<div v-if="currentAlgo === 'sliding'" class="sliding-window-vis">
|
||||
<div
|
||||
v-if="currentAlgo === 'sliding'"
|
||||
class="sliding-window-vis"
|
||||
>
|
||||
<div class="window-container">
|
||||
<div class="window-label">⏰ 时间窗口(过去1分钟)</div>
|
||||
<div class="window-label">
|
||||
⏰ 时间窗口(过去1分钟)
|
||||
</div>
|
||||
<div class="window-timeline">
|
||||
<div class="time-marks">
|
||||
<span v-for="n in 6" :key="n">{{ 60 - (n - 1) * 10 }}s</span>
|
||||
<span
|
||||
v-for="n in 6"
|
||||
:key="n"
|
||||
>{{ 60 - (n - 1) * 10 }}s</span>
|
||||
</div>
|
||||
<div class="window-bars">
|
||||
<div
|
||||
@@ -129,7 +180,10 @@
|
||||
:class="{ active: slot.count > 0, current: index === slidingWindow.currentSlot }"
|
||||
:style="{ height: `${Math.min((slot.count / 20) * 100, 100)}%` }"
|
||||
>
|
||||
<span class="slot-count" v-if="slot.count > 0">{{ slot.count }}</span>
|
||||
<span
|
||||
v-if="slot.count > 0"
|
||||
class="slot-count"
|
||||
>{{ slot.count }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -144,7 +198,10 @@
|
||||
</div>
|
||||
<div class="stat">
|
||||
<span class="stat-label">剩余额度:</span>
|
||||
<span class="stat-value" :class="{ warning: slidingWindow.remaining < 20 }">{{ slidingWindow.remaining }}</span>
|
||||
<span
|
||||
class="stat-value"
|
||||
:class="{ warning: slidingWindow.remaining < 20 }"
|
||||
>{{ slidingWindow.remaining }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -152,7 +209,9 @@
|
||||
</div>
|
||||
|
||||
<div class="comparison-section">
|
||||
<div class="section-title">📊 三种算法对比</div>
|
||||
<div class="section-title">
|
||||
📊 三种算法对比
|
||||
</div>
|
||||
<table class="comparison-table">
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -164,31 +223,41 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="dim">核心思想</td>
|
||||
<td class="dim">
|
||||
核心思想
|
||||
</td>
|
||||
<td>桶里装令牌,有令牌才能通过</td>
|
||||
<td>请求进桶,匀速流出处理</td>
|
||||
<td>统计时间窗口内的请求数</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="dim">突发流量</td>
|
||||
<td class="dim">
|
||||
突发流量
|
||||
</td>
|
||||
<td>✅ 允许一定程度的突发(桶里有令牌)</td>
|
||||
<td>❌ 强制平滑,突发会被缓存或拒绝</td>
|
||||
<td>❌ 严格按窗口计数,超出一律拒绝</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="dim">适用场景</td>
|
||||
<td class="dim">
|
||||
适用场景
|
||||
</td>
|
||||
<td>API 限流、带宽控制(允许突发)</td>
|
||||
<td>需要严格匀速处理的场景(如消息队列)</td>
|
||||
<td>精确统计(如"1分钟内最多100次")</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="dim">实现复杂度</td>
|
||||
<td class="dim">
|
||||
实现复杂度
|
||||
</td>
|
||||
<td>中等</td>
|
||||
<td>中等</td>
|
||||
<td>较高(需要记录每个时间窗口的请求)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="dim">Nginx 配置</td>
|
||||
<td class="dim">
|
||||
Nginx 配置
|
||||
</td>
|
||||
<td>limit_req_zone (漏桶)</td>
|
||||
<td>limit_req_zone (漏桶)</td>
|
||||
<td>需第三方模块或 Lua</td>
|
||||
@@ -198,7 +267,9 @@
|
||||
</div>
|
||||
|
||||
<div class="nginx-config">
|
||||
<div class="config-title">📝 Nginx 限流配置示例</div>
|
||||
<div class="config-title">
|
||||
📝 Nginx 限流配置示例
|
||||
</div>
|
||||
<div class="config-tabs">
|
||||
<button
|
||||
v-for="config in nginxConfigs"
|
||||
@@ -211,9 +282,16 @@
|
||||
</div>
|
||||
<pre class="config-code"><code>{{ currentNginxConfig.code }}</code></pre>
|
||||
<div class="config-explanation">
|
||||
<div class="exp-title">💡 配置说明</div>
|
||||
<div class="exp-title">
|
||||
💡 配置说明
|
||||
</div>
|
||||
<ul>
|
||||
<li v-for="(item, index) in currentNginxConfig.explanation" :key="index">{{ item }}</li>
|
||||
<li
|
||||
v-for="(item, index) in currentNginxConfig.explanation"
|
||||
:key="index"
|
||||
>
|
||||
{{ item }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -5,8 +5,12 @@
|
||||
<template>
|
||||
<div class="reverse-proxy-demo">
|
||||
<div class="header">
|
||||
<div class="title">🔄 反向代理 vs 正向代理</div>
|
||||
<div class="subtitle">一句话区分:正向代理是"客户端的代理",反向代理是"服务器的代理"</div>
|
||||
<div class="title">
|
||||
🔄 反向代理 vs 正向代理
|
||||
</div>
|
||||
<div class="subtitle">
|
||||
一句话区分:正向代理是"客户端的代理",反向代理是"服务器的代理"
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mode-selector">
|
||||
@@ -25,52 +29,104 @@
|
||||
</div>
|
||||
|
||||
<div class="flow-container">
|
||||
<div class="flow-row" v-if="mode === 'forward'">
|
||||
<div
|
||||
v-if="mode === 'forward'"
|
||||
class="flow-row"
|
||||
>
|
||||
<div class="flow-card client">
|
||||
<div class="icon">👤</div>
|
||||
<div class="label">用户 (想翻墙)</div>
|
||||
<div class="icon">
|
||||
👤
|
||||
</div>
|
||||
<div class="label">
|
||||
用户 (想翻墙)
|
||||
</div>
|
||||
</div>
|
||||
<div class="arrow-box">
|
||||
<div class="arrow">→</div>
|
||||
<div class="note">发给代理</div>
|
||||
<div class="arrow">
|
||||
→
|
||||
</div>
|
||||
<div class="note">
|
||||
发给代理
|
||||
</div>
|
||||
</div>
|
||||
<div class="flow-card proxy forward">
|
||||
<div class="icon">🔓</div>
|
||||
<div class="label">正向代理 (VPN/SS)</div>
|
||||
<div class="tag">代理客户端</div>
|
||||
<div class="icon">
|
||||
🔓
|
||||
</div>
|
||||
<div class="label">
|
||||
正向代理 (VPN/SS)
|
||||
</div>
|
||||
<div class="tag">
|
||||
代理客户端
|
||||
</div>
|
||||
</div>
|
||||
<div class="arrow-box">
|
||||
<div class="arrow">→</div>
|
||||
<div class="note">转发请求</div>
|
||||
<div class="arrow">
|
||||
→
|
||||
</div>
|
||||
<div class="note">
|
||||
转发请求
|
||||
</div>
|
||||
</div>
|
||||
<div class="flow-card target">
|
||||
<div class="icon">🌐</div>
|
||||
<div class="label">目标网站 (Google)</div>
|
||||
<div class="icon">
|
||||
🌐
|
||||
</div>
|
||||
<div class="label">
|
||||
目标网站 (Google)
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flow-row" v-if="mode === 'reverse'">
|
||||
<div
|
||||
v-if="mode === 'reverse'"
|
||||
class="flow-row"
|
||||
>
|
||||
<div class="flow-card client">
|
||||
<div class="icon">👤</div>
|
||||
<div class="label">用户 (浏览器)</div>
|
||||
<div class="icon">
|
||||
👤
|
||||
</div>
|
||||
<div class="label">
|
||||
用户 (浏览器)
|
||||
</div>
|
||||
</div>
|
||||
<div class="arrow-box">
|
||||
<div class="arrow">→</div>
|
||||
<div class="note">访问域名</div>
|
||||
<div class="arrow">
|
||||
→
|
||||
</div>
|
||||
<div class="note">
|
||||
访问域名
|
||||
</div>
|
||||
</div>
|
||||
<div class="flow-card proxy reverse">
|
||||
<div class="icon">🛡️</div>
|
||||
<div class="label">反向代理 (Nginx)</div>
|
||||
<div class="tag">代理服务器</div>
|
||||
<div class="icon">
|
||||
🛡️
|
||||
</div>
|
||||
<div class="label">
|
||||
反向代理 (Nginx)
|
||||
</div>
|
||||
<div class="tag">
|
||||
代理服务器
|
||||
</div>
|
||||
</div>
|
||||
<div class="arrow-box">
|
||||
<div class="arrow">→</div>
|
||||
<div class="note">负载均衡</div>
|
||||
<div class="arrow">
|
||||
→
|
||||
</div>
|
||||
<div class="note">
|
||||
负载均衡
|
||||
</div>
|
||||
</div>
|
||||
<div class="flow-card server">
|
||||
<div class="icon">⚙️</div>
|
||||
<div class="label">后端服务器集群</div>
|
||||
<div class="sub-label">Web1 | Web2 | Web3</div>
|
||||
<div class="icon">
|
||||
⚙️
|
||||
</div>
|
||||
<div class="label">
|
||||
后端服务器集群
|
||||
</div>
|
||||
<div class="sub-label">
|
||||
Web1 | Web2 | Web3
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -81,19 +137,33 @@
|
||||
{{ mode === 'forward' ? '🔓 正向代理特点' : '🛡️ 反向代理特点' }}
|
||||
</div>
|
||||
<ul class="detail-list">
|
||||
<li v-for="(item, index) in currentFeatures" :key="index">{{ item }}</li>
|
||||
<li
|
||||
v-for="(item, index) in currentFeatures"
|
||||
:key="index"
|
||||
>
|
||||
{{ item }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="detail-card">
|
||||
<div class="detail-title">💡 典型使用场景</div>
|
||||
<div class="detail-title">
|
||||
💡 典型使用场景
|
||||
</div>
|
||||
<ul class="detail-list">
|
||||
<li v-for="(item, index) in currentScenarios" :key="index">{{ item }}</li>
|
||||
<li
|
||||
v-for="(item, index) in currentScenarios"
|
||||
:key="index"
|
||||
>
|
||||
{{ item }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="memory-trick">
|
||||
<div class="trick-title">🧠 记忆口诀</div>
|
||||
<div class="trick-title">
|
||||
🧠 记忆口诀
|
||||
</div>
|
||||
<div class="trick-content">
|
||||
<p v-if="mode === 'forward'">
|
||||
<strong>"正向代理 = 代理客户端"</strong> —— 客户端知情,服务器只知道代理IP
|
||||
|
||||
@@ -5,56 +5,86 @@
|
||||
<template>
|
||||
<div class="routing-rules-demo">
|
||||
<div class="header">
|
||||
<div class="title">🧭 路由规则:如何把请求送到正确的服务?</div>
|
||||
<div class="subtitle">想象成快递分拣中心——根据地址把包裹分配到不同的配送站</div>
|
||||
<div class="title">
|
||||
🧭 路由规则:如何把请求送到正确的服务?
|
||||
</div>
|
||||
<div class="subtitle">
|
||||
想象成快递分拣中心——根据地址把包裹分配到不同的配送站
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="playground">
|
||||
<div class="playground-header">
|
||||
<div class="playground-title">🎮 路由规则实验室</div>
|
||||
<div class="playground-subtitle">输入一个 URL,看看它会被路由到哪个服务</div>
|
||||
<div class="playground-title">
|
||||
🎮 路由规则实验室
|
||||
</div>
|
||||
<div class="playground-subtitle">
|
||||
输入一个 URL,看看它会被路由到哪个服务
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="input-section">
|
||||
<div class="input-group">
|
||||
<label>HTTP 方法</label>
|
||||
<select v-model="request.method">
|
||||
<option value="GET">GET</option>
|
||||
<option value="POST">POST</option>
|
||||
<option value="PUT">PUT</option>
|
||||
<option value="DELETE">DELETE</option>
|
||||
<option value="GET">
|
||||
GET
|
||||
</option>
|
||||
<option value="POST">
|
||||
POST
|
||||
</option>
|
||||
<option value="PUT">
|
||||
PUT
|
||||
</option>
|
||||
<option value="DELETE">
|
||||
DELETE
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="input-group flex-2">
|
||||
<label>URL 路径</label>
|
||||
<input
|
||||
type="text"
|
||||
v-model="request.path"
|
||||
type="text"
|
||||
placeholder="/api/users/123"
|
||||
@keyup.enter="matchRoute"
|
||||
/>
|
||||
>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<label>Header (可选)</label>
|
||||
<input
|
||||
type="text"
|
||||
v-model="request.header"
|
||||
type="text"
|
||||
placeholder="X-Version: v2"
|
||||
/>
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="match-btn" @click="matchRoute" :disabled="isMatching">
|
||||
<button
|
||||
class="match-btn"
|
||||
:disabled="isMatching"
|
||||
@click="matchRoute"
|
||||
>
|
||||
{{ isMatching ? '匹配中...' : '🔍 开始匹配' }}
|
||||
</button>
|
||||
|
||||
<div class="result-section" v-if="matchResult">
|
||||
<div
|
||||
v-if="matchResult"
|
||||
class="result-section"
|
||||
>
|
||||
<div :class="['result-card', matchResult.found ? 'success' : 'fail']">
|
||||
<div class="result-header">
|
||||
<div class="result-icon">{{ matchResult.found ? '✅' : '❌' }}</div>
|
||||
<div class="result-title">{{ matchResult.found ? '匹配成功' : '未找到匹配规则' }}</div>
|
||||
<div class="result-icon">
|
||||
{{ matchResult.found ? '✅' : '❌' }}
|
||||
</div>
|
||||
<div class="result-title">
|
||||
{{ matchResult.found ? '匹配成功' : '未找到匹配规则' }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="result-detail" v-if="matchResult.found">
|
||||
<div
|
||||
v-if="matchResult.found"
|
||||
class="result-detail"
|
||||
>
|
||||
<div class="detail-row">
|
||||
<span class="label">目标服务:</span>
|
||||
<span class="value service">{{ matchResult.service }}</span>
|
||||
@@ -72,7 +102,10 @@
|
||||
<span class="value url">{{ matchResult.targetUrl }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="result-suggestion" v-else>
|
||||
<div
|
||||
v-else
|
||||
class="result-suggestion"
|
||||
>
|
||||
<p>💡 建议检查:</p>
|
||||
<ul>
|
||||
<li>路径是否以 /api 开头?</li>
|
||||
@@ -85,7 +118,9 @@
|
||||
</div>
|
||||
|
||||
<div class="rules-table">
|
||||
<div class="table-title">📋 当前路由规则表</div>
|
||||
<div class="table-title">
|
||||
📋 当前路由规则表
|
||||
</div>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -96,19 +131,29 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(rule, index) in routingRules" :key="index"
|
||||
:class="{ active: matchResult && matchResult.ruleIndex === index }">
|
||||
<tr
|
||||
v-for="(rule, index) in routingRules"
|
||||
:key="index"
|
||||
:class="{ active: matchResult && matchResult.ruleIndex === index }"
|
||||
>
|
||||
<td>{{ index + 1 }}</td>
|
||||
<td><code>{{ rule.match }}</code></td>
|
||||
<td><span class="service-tag">{{ rule.service }}</span></td>
|
||||
<td><code v-if="rule.rewrite">{{ rule.rewrite }}</code><span v-else class="no-rewrite">无</span></td>
|
||||
<td>
|
||||
<code v-if="rule.rewrite">{{ rule.rewrite }}</code><span
|
||||
v-else
|
||||
class="no-rewrite"
|
||||
>无</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="quick-presets">
|
||||
<div class="presets-title">🚀 快速测试示例</div>
|
||||
<div class="presets-title">
|
||||
🚀 快速测试示例
|
||||
</div>
|
||||
<div class="preset-buttons">
|
||||
<button
|
||||
v-for="preset in presets"
|
||||
|
||||
@@ -5,69 +5,111 @@
|
||||
<template>
|
||||
<div class="ssl-termination-demo">
|
||||
<div class="header">
|
||||
<div class="title">🔒 SSL 终结:HTTPS 流量的"解密官"</div>
|
||||
<div class="subtitle">想象成公司的前台接待——对外使用正式头衔(HTTPS),对内用内部称呼(HTTP),负责"翻译"身份</div>
|
||||
<div class="title">
|
||||
🔒 SSL 终结:HTTPS 流量的"解密官"
|
||||
</div>
|
||||
<div class="subtitle">
|
||||
想象成公司的前台接待——对外使用正式头衔(HTTPS),对内用内部称呼(HTTP),负责"翻译"身份
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ssl-flow">
|
||||
<div class="flow-title">🔐 HTTPS 流量解密流程</div>
|
||||
<div class="flow-title">
|
||||
🔐 HTTPS 流量解密流程
|
||||
</div>
|
||||
|
||||
<div class="flow-diagram">
|
||||
<!-- 客户端 -->
|
||||
<div class="flow-node client">
|
||||
<div class="node-icon">👤</div>
|
||||
<div class="node-label">客户端 (浏览器)</div>
|
||||
<div class="node-detail">发起 HTTPS 请求</div>
|
||||
<div class="node-icon">
|
||||
👤
|
||||
</div>
|
||||
<div class="node-label">
|
||||
客户端 (浏览器)
|
||||
</div>
|
||||
<div class="node-detail">
|
||||
发起 HTTPS 请求
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flow-arrow encrypted">
|
||||
<div class="arrow-line"></div>
|
||||
<div class="arrow-line" />
|
||||
<div class="arrow-label">
|
||||
<span class="lock-icon">🔒</span>
|
||||
<span>TLS 加密连接</span>
|
||||
</div>
|
||||
<div class="cert-info">
|
||||
<div class="cert-item"><span class="cert-label">证书:</span> *.example.com</div>
|
||||
<div class="cert-item"><span class="cert-label">算法:</span> TLS 1.3</div>
|
||||
<div class="cert-item"><span class="cert-label">加密:</span> AES-256-GCM</div>
|
||||
<div class="cert-item">
|
||||
<span class="cert-label">证书:</span> *.example.com
|
||||
</div>
|
||||
<div class="cert-item">
|
||||
<span class="cert-label">算法:</span> TLS 1.3
|
||||
</div>
|
||||
<div class="cert-item">
|
||||
<span class="cert-label">加密:</span> AES-256-GCM
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Nginx -->
|
||||
<div class="flow-node nginx">
|
||||
<div class="node-icon">🚪</div>
|
||||
<div class="node-label">Nginx (SSL 终结)</div>
|
||||
<div class="node-icon">
|
||||
🚪
|
||||
</div>
|
||||
<div class="node-label">
|
||||
Nginx (SSL 终结)
|
||||
</div>
|
||||
<div class="node-actions">
|
||||
<div class="action"><span class="action-icon">📜</span> 校验证书</div>
|
||||
<div class="action"><span class="action-icon">🔓</span> 解密流量</div>
|
||||
<div class="action"><span class="action-icon">📝</span> 添加 X-Forwarded-*</div>
|
||||
<div class="action">
|
||||
<span class="action-icon">📜</span> 校验证书
|
||||
</div>
|
||||
<div class="action">
|
||||
<span class="action-icon">🔓</span> 解密流量
|
||||
</div>
|
||||
<div class="action">
|
||||
<span class="action-icon">📝</span> 添加 X-Forwarded-*
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flow-arrow plain">
|
||||
<div class="arrow-line"></div>
|
||||
<div class="arrow-line" />
|
||||
<div class="arrow-label">
|
||||
<span class="unlock-icon">🔓</span>
|
||||
<span>HTTP 明文</span>
|
||||
</div>
|
||||
<div class="headers-info">
|
||||
<div class="header-item">X-Forwarded-For: 203.0.113.42</div>
|
||||
<div class="header-item">X-Forwarded-Proto: https</div>
|
||||
<div class="header-item">X-Real-IP: 203.0.113.42</div>
|
||||
<div class="header-item">
|
||||
X-Forwarded-For: 203.0.113.42
|
||||
</div>
|
||||
<div class="header-item">
|
||||
X-Forwarded-Proto: https
|
||||
</div>
|
||||
<div class="header-item">
|
||||
X-Real-IP: 203.0.113.42
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 后端服务 -->
|
||||
<div class="flow-node backend">
|
||||
<div class="node-icon">⚙️</div>
|
||||
<div class="node-label">后端服务集群</div>
|
||||
<div class="node-detail">专注于业务逻辑,无需处理 TLS</div>
|
||||
<div class="node-icon">
|
||||
⚙️
|
||||
</div>
|
||||
<div class="node-label">
|
||||
后端服务集群
|
||||
</div>
|
||||
<div class="node-detail">
|
||||
专注于业务逻辑,无需处理 TLS
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="cert-management">
|
||||
<div class="section-title">📜 SSL 证书管理</div>
|
||||
<div class="section-title">
|
||||
📜 SSL 证书管理
|
||||
</div>
|
||||
|
||||
<div class="cert-tabs">
|
||||
<button
|
||||
@@ -82,14 +124,30 @@
|
||||
|
||||
<div class="cert-content">
|
||||
<!-- 证书申请流程 -->
|
||||
<div v-if="currentCertTab === 'apply'" class="apply-flow">
|
||||
<div
|
||||
v-if="currentCertTab === 'apply'"
|
||||
class="apply-flow"
|
||||
>
|
||||
<div class="flow-steps">
|
||||
<div v-for="(step, index) in certSteps" :key="index" class="cert-step">
|
||||
<div class="step-badge">{{ index + 1 }}</div>
|
||||
<div
|
||||
v-for="(step, index) in certSteps"
|
||||
:key="index"
|
||||
class="cert-step"
|
||||
>
|
||||
<div class="step-badge">
|
||||
{{ index + 1 }}
|
||||
</div>
|
||||
<div class="step-content">
|
||||
<div class="step-title">{{ step.title }}</div>
|
||||
<div class="step-desc">{{ step.desc }}</div>
|
||||
<div class="step-command" v-if="step.command">
|
||||
<div class="step-title">
|
||||
{{ step.title }}
|
||||
</div>
|
||||
<div class="step-desc">
|
||||
{{ step.desc }}
|
||||
</div>
|
||||
<div
|
||||
v-if="step.command"
|
||||
class="step-command"
|
||||
>
|
||||
<code>{{ step.command }}</code>
|
||||
</div>
|
||||
</div>
|
||||
@@ -98,7 +156,10 @@
|
||||
</div>
|
||||
|
||||
<!-- Nginx 配置 -->
|
||||
<div v-if="currentCertTab === 'config'" class="nginx-config">
|
||||
<div
|
||||
v-if="currentCertTab === 'config'"
|
||||
class="nginx-config"
|
||||
>
|
||||
<pre class="config-block"><code>server {
|
||||
listen 443 ssl http2;
|
||||
server_name api.example.com;
|
||||
@@ -147,15 +208,27 @@ server {
|
||||
</div>
|
||||
|
||||
<!-- 最佳实践 -->
|
||||
<div v-if="currentCertTab === 'bestpractice'" class="best-practices">
|
||||
<div
|
||||
v-if="currentCertTab === 'bestpractice'"
|
||||
class="best-practices"
|
||||
>
|
||||
<div class="practices-grid">
|
||||
<div v-for="practice in bestPractices" :key="practice.id" class="practice-card">
|
||||
<div
|
||||
v-for="practice in bestPractices"
|
||||
:key="practice.id"
|
||||
class="practice-card"
|
||||
>
|
||||
<div class="practice-header">
|
||||
<span class="practice-icon">{{ practice.icon }}</span>
|
||||
<span class="practice-title">{{ practice.title }}</span>
|
||||
</div>
|
||||
<div class="practice-content">{{ practice.content }}</div>
|
||||
<div class="practice-code" v-if="practice.code">
|
||||
<div class="practice-content">
|
||||
{{ practice.content }}
|
||||
</div>
|
||||
<div
|
||||
v-if="practice.code"
|
||||
class="practice-code"
|
||||
>
|
||||
<code>{{ practice.code }}</code>
|
||||
</div>
|
||||
</div>
|
||||
@@ -165,31 +238,57 @@ server {
|
||||
</div>
|
||||
|
||||
<div class="benefits-section">
|
||||
<div class="section-title">✨ SSL 终结的核心优势</div>
|
||||
<div class="section-title">
|
||||
✨ SSL 终结的核心优势
|
||||
</div>
|
||||
|
||||
<div class="benefits-grid">
|
||||
<div class="benefit-card">
|
||||
<div class="benefit-icon">🚀</div>
|
||||
<div class="benefit-title">性能提升</div>
|
||||
<div class="benefit-desc">TLS 握手和加密解密是 CPU 密集型操作,集中在 Nginx 处理,后端服务专注业务逻辑,整体吞吐量提升 2-5 倍</div>
|
||||
<div class="benefit-icon">
|
||||
🚀
|
||||
</div>
|
||||
<div class="benefit-title">
|
||||
性能提升
|
||||
</div>
|
||||
<div class="benefit-desc">
|
||||
TLS 握手和加密解密是 CPU 密集型操作,集中在 Nginx 处理,后端服务专注业务逻辑,整体吞吐量提升 2-5 倍
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="benefit-card">
|
||||
<div class="benefit-icon">🔧</div>
|
||||
<div class="benefit-title">简化运维</div>
|
||||
<div class="benefit-desc">证书统一管理,只需在 Nginx 配置一次,无需在每个后端服务重复配置,证书续期、更换一键完成</div>
|
||||
<div class="benefit-icon">
|
||||
🔧
|
||||
</div>
|
||||
<div class="benefit-title">
|
||||
简化运维
|
||||
</div>
|
||||
<div class="benefit-desc">
|
||||
证书统一管理,只需在 Nginx 配置一次,无需在每个后端服务重复配置,证书续期、更换一键完成
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="benefit-card">
|
||||
<div class="benefit-icon">🛡️</div>
|
||||
<div class="benefit-title">集中安全</div>
|
||||
<div class="benefit-desc">SSL/TLS 配置统一管控,强制使用最新协议版本和密码套件,统一添加安全响应头(HSTS、CSP 等)</div>
|
||||
<div class="benefit-icon">
|
||||
🛡️
|
||||
</div>
|
||||
<div class="benefit-title">
|
||||
集中安全
|
||||
</div>
|
||||
<div class="benefit-desc">
|
||||
SSL/TLS 配置统一管控,强制使用最新协议版本和密码套件,统一添加安全响应头(HSTS、CSP 等)
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="benefit-card">
|
||||
<div class="benefit-icon">📊</div>
|
||||
<div class="benefit-title">统一监控</div>
|
||||
<div class="benefit-desc">所有 HTTPS 流量经过 Nginx,可以统一记录访问日志、分析 SSL 握手性能、监控证书有效期,便于审计和排障</div>
|
||||
<div class="benefit-icon">
|
||||
📊
|
||||
</div>
|
||||
<div class="benefit-title">
|
||||
统一监控
|
||||
</div>
|
||||
<div class="benefit-desc">
|
||||
所有 HTTPS 流量经过 Nginx,可以统一记录访问日志、分析 SSL 握手性能、监控证书有效期,便于审计和排障
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user