面试题答案
一键面试资源预处理
- 压缩:
- 对于图片,使用
image - webpack - loader
等工具对常见图片格式(如 JPEG、PNG、SVG)进行压缩。例如,在 Node.js 项目中,如果使用 Webpack 构建,可以配置如下:
module.exports = { module: { rules: [ { test: /\.(png|jpg|jpeg|svg)$/, use: [ { loader: 'image - webpack - loader', options: { mozjpeg: { progressive: true, quality: 65 }, // optipng.enabled: false will disable optipng optipng: { enabled: false }, pngquant: { quality: [0.65, 0.90], speed: 4 }, gifsicle: { interlaced: false }, // the webp option will enable WEBP webp: { quality: 75 } } } ] } ] } };
- 对于脚本(JavaScript)和样式文件(CSS),使用工具如
uglify - js
压缩 JavaScript,cssnano
压缩 CSS。在 Webpack 中配置如下:
const UglifyJsPlugin = require('uglifyjs - webpack - plugin'); const OptimizeCSSAssetsPlugin = require('optimize - css - assets - plugin'); module.exports = { optimization: { minimizer: [ new UglifyJsPlugin({ cache: true, parallel: true, sourceMap: true }), new OptimizeCSSAssetsPlugin({}) ] } };
- 对于图片,使用
- 合并:
- 将多个小的脚本和样式文件合并成较大的文件,减少 HTTP 请求数。在 Webpack 中,可以通过
webpack - merge
等插件来实现。例如,对于 CSS 文件,可以使用extract - text - webpack - plugin
将所有 CSS 提取到一个文件中:
const ExtractTextPlugin = require('extract - text - webpack - plugin'); module.exports = { module: { rules: [ { test: /\.css$/, use: ExtractTextPlugin.extract({ fallback: 'style - loader', use: 'css - loader' }) } ] }, plugins: [ new ExtractTextPlugin('styles.css') ] };
- 将多个小的脚本和样式文件合并成较大的文件,减少 HTTP 请求数。在 Webpack 中,可以通过
CDN 节点选择
- 基于地理位置:
- 使用 MaxMind 的 GeoIP 数据库,结合 Node.js 的
geoip - lite
库(或更高级的商业版本)。在 Node.js 服务启动时,加载 GeoIP 数据库,当请求到达时,通过解析客户端 IP 获取其地理位置,然后根据地理位置选择最近的 CDN 节点。例如:
const geoip = require('geoip - lite'); app.get('/getCDNNode', (req, res) => { const ip = req.headers['x - forward - for'] || req.connection.remoteAddress; const geo = geoip.lookup(ip); if (geo) { // 根据 geo.country 或 geo.region 选择 CDN 节点 const cdnNode = getCDNNodeBasedOnLocation(geo.country); res.json({ cdnNode }); } else { res.json({ cdnNode: 'default - cdn - node' }); } });
- 使用 MaxMind 的 GeoIP 数据库,结合 Node.js 的
- 基于网络状况:
- 一些 CDN 提供商(如 Akamai)提供基于网络状况的节点选择功能。可以通过 CDN 提供的 SDK 或 API,实时监测客户端到不同 CDN 节点的网络延迟、带宽等指标,动态选择最佳节点。例如,通过定期向 CDN 提供的监测接口发送请求,获取网络状况数据,然后根据算法选择最优节点。
回源策略
- 缓存过期回源:
- 在 CDN 节点上设置合理的缓存过期时间。对于不常变动的静态资源(如长期不变的样式文件、脚本文件),设置较长的缓存过期时间(如一年)。当缓存过期后,CDN 节点向源站(Node.js 子服务)请求最新资源。可以在 Node.js 服务端设置
Cache - Control
头来控制缓存行为。例如,在 Express 应用中:
app.get('/static/styles.css', (req, res) => { res.set('Cache - Control','max - age = 31536000, public'); // 一年的缓存时间 res.sendFile(path.join(__dirname,'static','styles.css')); });
- 在 CDN 节点上设置合理的缓存过期时间。对于不常变动的静态资源(如长期不变的样式文件、脚本文件),设置较长的缓存过期时间(如一年)。当缓存过期后,CDN 节点向源站(Node.js 子服务)请求最新资源。可以在 Node.js 服务端设置
- 版本控制回源:
- 为静态资源添加版本号。在 Node.js 项目构建时,通过 Webpack 的
hash
功能为文件命名添加版本标识。例如:
当资源版本发生变化时,CDN 节点会向源站回源获取新的资源。module.exports = { output: { filename: 'bundle.[hash].js' } };
- 为静态资源添加版本号。在 Node.js 项目构建时,通过 Webpack 的
Node.js 各子服务间协同
- 负载均衡:
- 使用
nginx
或HAProxy
作为反向代理和负载均衡器,将请求均匀分配到不同的 Node.js 子服务上。例如,在nginx
配置中:
upstream node - services { server 192.168.1.10:3000; server 192.168.1.11:3000; } server { listen 80; location / { proxy_pass http://node - services; } }
- 使用
- 资源分配与管理:
- 每个 Node.js 子服务负责特定类型的静态资源。可以通过在配置文件中定义资源类型与子服务的映射关系,例如:
当需要获取资源时,通过该映射找到对应的子服务。const resourceServiceMap = { 'images': 'image - service - url', 'scripts':'script - service - url', 'styles':'style - service - url' };
安全性
- HTTPS:
- 在 Node.js 子服务和 CDN 节点上启用 HTTPS。可以使用 Let's Encrypt 免费证书,在 Node.js 中,通过
https
模块结合证书文件来启动 HTTPS 服务:
const https = require('https'); const fs = require('fs'); const options = { key: fs.readFileSync('privatekey.pem'), cert: fs.readFileSync('certificate.pem') }; https.createServer(options, app).listen(443);
- 在 Node.js 子服务和 CDN 节点上启用 HTTPS。可以使用 Let's Encrypt 免费证书,在 Node.js 中,通过
- 访问控制:
- 在 Node.js 子服务端设置严格的访问控制策略。使用
cors
中间件在 Express 应用中设置允许的跨域来源:
在 CDN 层面,也可以配置访问控制规则,限制对资源的访问。const express = require('express'); const app = express(); const cors = require('cors'); app.use(cors({ origin: 'https://allowed - domain.com' }));
- 在 Node.js 子服务端设置严格的访问控制策略。使用
成本控制
- 按需选择 CDN 套餐:
- 根据业务流量预估,选择合适的 CDN 套餐。一些 CDN 提供商提供按流量、按请求数等多种计费方式。分析业务流量模式,选择最经济的计费方式。例如,如果业务流量较为稳定且可预测,可以选择按固定流量套餐计费;如果流量波动较大,可以选择按实际使用流量计费。
- 优化资源大小:
- 通过前面提到的资源预处理(压缩、合并),减少资源大小,从而降低 CDN 传输成本。因为 CDN 费用通常与传输的数据量相关,减小资源大小可以有效降低成本。
可扩展性
- 水平扩展:
- 对于 Node.js 子服务,可以通过增加服务器实例进行水平扩展。使用容器化技术(如 Docker)和容器编排工具(如 Kubernetes),方便地管理和扩展子服务。例如,在 Kubernetes 中,可以通过修改
Deployment
的副本数来扩展服务:
apiVersion: apps/v1 kind: Deployment metadata: name: image - service - deployment spec: replicas: 3 selector: matchLabels: app: image - service template: metadata: labels: app: image - service spec: containers: - name: image - service - container image: image - service - image:latest ports: - containerPort: 3000
- 对于 Node.js 子服务,可以通过增加服务器实例进行水平扩展。使用容器化技术(如 Docker)和容器编排工具(如 Kubernetes),方便地管理和扩展子服务。例如,在 Kubernetes 中,可以通过修改
- CDN 扩展:
- 当业务增长时,选择支持更多节点和更高流量的 CDN 套餐,或者考虑使用多个 CDN 提供商进行冗余和扩展。一些 CDN 提供商提供无缝升级套餐的功能,方便根据业务需求动态调整。