当前位置: 首页 > news >正文

前端接口安全与性能优化实战

文章目录

  • 接口请求封装
    • 请求拦截器
      • 设置请求头防止重放攻击:
        • X-Timestamp 时间戳
        • X-Nonce 长度16位的随机字符串
        • X-Signateure api请求签名
        • X-Client-ID 客户端id
    • 响应拦截器
    • 缓存接口数据防止重复请求
    • 职责链模式
  • 用时间切片优化项目速度
  • webworker执行耗时任务
    • 注意事项
  • vue2项目改用vite
  • 从资源加载优化角度加速项目
  • 浏览器缓存的两种机制
    • 强缓存
    • 协商缓存

接口请求封装

请求拦截器

请求前

设置请求头防止重放攻击:

X-Timestamp 时间戳

后端代码

/*** 验证时间戳有效性(例如5分钟内有效)*/private boolean isValidTimestamp(String timestampStr, HttpServletResponse response) throws IOException {if (timestampStr == null) {sendErrorResponse(response, "缺少时间戳");return false;}try {long timestamp = Long.parseLong(timestampStr);long currentTime = System.currentTimeMillis();long timeDiff = Math.abs(currentTime - timestamp);if (timeDiff > 5 * 60 * 1000) {sendErrorResponse(response, "请求已过期");return false;}} catch (NumberFormatException e) {sendErrorResponse(response, "时间戳格式错误");return false;}return true;}
X-Nonce 长度16位的随机字符串
/*** 验证随机字符串有效性** @param nonce* @param response* @return* @throws IOException*/private boolean isValidNonce(String nonce, HttpServletResponse response) throws IOException {if (nonce == null || nonce.isEmpty()) {sendErrorResponse(response, "缺少随机字符串");return false;}// 验证nonce是否已使用(防止重放攻击)String nonceKey = "nonce:" + nonce;Boolean isNewNonce = redisTemplate.opsForValue().setIfAbsent(nonceKey, "1", 5, TimeUnit.MINUTES);if (Boolean.FALSE.equals(isNewNonce)) {sendErrorResponse(response, "重复的请求");return false;}return true;}
X-Signateure api请求签名
// 生成请求签名
export function generateSignature(secretKey, method, url, timestamp, nonce, body = '') {const key = String(secretKey || '')const httpMethod = String(method || '').toUpperCase()const requestUrl = String(url || '')const time = String(timestamp || '')const nonceStr = String(nonce || '')const finalUrl = processUrl(requestUrl)const bodyStr = serializeBody(httpMethod, body)const data = buildSignatureData(httpMethod, finalUrl, time, nonceStr, bodyStr)console.log('Signature data:', data)const signature = sha256.hmac(key, data)console.log('Generated signature:', signature)return signature
}
/*** 验证签名有效性** @param signature* @param response* @param dataForSigning* @return* @throws IOException*/
private boolean isValidSignature(String signature, HttpServletResponse response, String dataForSigning) throws IOException {if (signature == null || signature.isEmpty()) {sendErrorResponse(response, "缺少签名");return true;}// 构造待签名数据(不包含请求体)log.info("Data for signing (multipart): {}", dataForSigning);// 计算签名String computedSignature = computeSignature(dataForSigning, clientSecret);log.info("Computed signature: {}", computedSignature);log.info("Received signature: {}", signature);// 验证签名if (!computedSignature.equals(signature)) {sendErrorResponse(response, "无效的签名");return true;}return false;
}
/*** 计算HMAC-SHA256签名*/
private String computeSignature(String data, String secret) {try {Mac mac = Mac.getInstance("HmacSHA256");SecretKeySpec secretKeySpec = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");mac.init(secretKeySpec);byte[] signatureBytes = mac.doFinal(data.getBytes(StandardCharsets.UTF_8));return bytesToHex(signatureBytes);} catch (Exception e) {log.error("签名计算失败", e);throw new RuntimeException("签名计算失败", e);}
}
X-Client-ID 客户端id

​ 如果token存在并且请求路径不是白名单则添加认证头Authorization

​ 为每个请求生成唯一标识

const requestId = `${config.url}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`
config.requestId = requestId

​ 只有当配置中 showLoading 不为 false 时才显示 loading或者进度条

​ 记录请求开始时间

请求失败

​ 请求错误时关闭 loading或者进度条

​ 关闭对应请求的 loading或者进度条

​ …

响应拦截器

成功

​ 响应成功时关闭对应请求的 loading或者进度条

​ 计算接口耗时

​ 如果response.data instanceof Blob return resopnse.data

​ 如果业务状态码表示成功则返回response.data.data

​ 其他情况:业务码[code]?.()

失败

​ 响应错误时关闭对应请求的 loading或者进度条

​ 计算接口耗时(即使出错也记录)

​ 处理401状态码清除token跳转到登录页或刷新token,拿短token换长token

​ 处理其他错误:httpErrorCode[status]?.()

image-20251107233636694

缓存接口数据防止重复请求

image-20251108221700688

职责链模式

缓存模块-》防止重复提交模块-》请求模块》请求处理模块

image-20251108230244408

image-20251108230222829

用时间切片优化项目速度

image-20251108190345530

image-20251108190419334

webworker执行耗时任务

注意事项

image-20251108192121094

image-20251108191704449

image-20251108191534457

vue2项目改用vite

删除node_modules

删除package.json中的开发依赖

删除babel配置文件

删除package.json中的eslint配置

删除postcss配置

image-20251108203411430

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

从资源加载优化角度加速项目

image-20251108232344884

image-20251108234324575

image-20251108233342510

image-20251108235022649

image-20251109000502985

浏览器缓存的两种机制

image-20251109133312011

强缓存

优点:一定期限内,根本不用向服务器询问,一定是拿到缓存。速度最快
缺点:如何不配合hash,无法感知到文件更新

image-20251109133821279

协商缓存

优点:能够保证每次前端打包后丢上服务器资源一定更新
缺点:只要文件是新放的,即使文件内容没变也不缓存

image-20251109134004119

http://www.dtcms.com/a/588876.html

相关文章:

  • ssh网站怎么做wordpress搬家_后台错乱
  • LangChain V1.0 Messages 详细指南
  • 网站商城微信支付接口申请软件开发人工收费标准
  • 代码生成与开发辅助
  • claude code访问本地部署的MCP服务
  • 学习笔记8
  • Vue编程式路由导航
  • android contentprovider及其查看
  • 根据网站做软件免费网站app下载
  • Rust 练习册 :解开两桶谜题的奥秘
  • 2025.11.03作业 WEB服务
  • Electron 应用中的系统检测方案对比
  • 秦皇岛 网站制作怎么做网站推广临沂
  • oj 数码积和(略难
  • RT-Thread开发实战 --- PIN设备的使用
  • Android的binder机制理解
  • 二十五、STM32的DMA(数据转运)
  • 湖北省建设厅政务公开网站wordpress加速网站插件
  • 提示词(Prompt)工程与推理优化
  • 简析单目相机模型中的针孔模型
  • Apache Flink CDC——变更数据捕获
  • 从“数据堆场”到“智能底座”:TDengine IDMP如何统一数据语言
  • 从细胞工厂到智能制造:Extracellular 用 TDengine 打通数据生命线
  • 哪里有建设网站的html展示wordpress
  • Windows 下编译 WhisperKit Android CLI 的解决方案
  • 【第二十一周】机器学习周报
  • 如何在 Ubuntu 24.04 上安装和使用 AdGuard
  • 传统的企业服务如何部署在k8s集群中
  • 【计算思维】蓝桥杯STEMA 科技素养考试真题及解析 2
  • 淘车车二手车数据采集:API接口分析与数据爬取实战