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

网站开发工作量及预算计算广东莞建建设工程有限公司

网站开发工作量及预算计算,广东莞建建设工程有限公司,淘宝优惠券网站建设教程,知名室内设计网站一、引言 前端接口防止重复请求的实现方案主要基于以下几个原因#xff1a; 用户体验#xff1a;重复发送请求可能导致页面长时间无响应或加载缓慢#xff0c;从而影响用户的体验。特别是在网络不稳定或请求处理时间较长的情况下#xff0c;这个问题尤为突出。 服务器压力… 一、引言 前端接口防止重复请求的实现方案主要基于以下几个原因 用户体验重复发送请求可能导致页面长时间无响应或加载缓慢从而影响用户的体验。特别是在网络不稳定或请求处理时间较长的情况下这个问题尤为突出。 服务器压力如果前端不限制重复请求服务器可能会接收到大量的重复请求这不仅增加了服务器的处理负担还可能导致资源浪费。 数据一致性对于某些操作如表单提交重复请求可能导致数据重复插入或更新从而破坏数据的一致性。 为了实现前端接口防止重复请求可以采取以下方案 设置请求标志在发送请求时为请求设置一个唯一的标识符如请求ID。在请求处理过程中可以通过检查该标识符来判断是否已存在相同的请求。如果存在则取消或忽略重复请求。 使用防抖debounce和节流throttle技术这两种技术都可以用来限制函数的执行频率。防抖是在一定时间间隔内只执行一次函数而节流是在一定时间间隔内最多执行一次函数。这两种技术可以有效防止用户频繁触发事件导致的重复请求。 取消未完成的请求在发送新的请求之前可以检查是否存在未完成的请求。如果存在则取消这些请求以避免重复发送。这通常可以通过使用Promise、AbortController等技术实现。 前端状态管理使用状态管理工具如Redux、Vuex等来管理请求状态。在发送请求前检查状态以确定是否已存在相同的请求。这种方案可以更加灵活地控制请求的行为。 后端接口设计虽然前端可以采取措施防止重复请求但后端接口的设计也非常重要。例如可以为接口设置幂等性确保即使多次调用接口也不会产生副作用。此外还可以使用令牌token等机制来限制请求的重复发送。 综合使用这些方案可以有效地防止前端接口的重复请求提高用户体验和系统的稳定性。 二、取消未完成的请求 1、Axios内置的 axios.CancelToken import type { AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig } from axios import axios from axiosconst CancelToken axios.CancelToken const queue: any [] // 请求队列const service axios.create({baseURL: /api,timeout: 10 * 60 * 1000,headers: {Content-Type: application/json;charsetUTF-8,}, })// 取消重复请求 const removeRepeatRequest (config: AxiosRequestConfig) {for (const key in queue) {const index keyconst item queue[key]if (item.url config.url item.method config.method JSON.stringify(item.params) JSON.stringify(config.params) JSON.stringify(item.data) JSON.stringify(config.data)) {// 执行取消操作item.cancel(操作太频繁请稍后再试)queue.splice(index, 1)}} }// 请求拦截器 service.interceptors.request.use((config: InternalAxiosRequestConfig) {removeRepeatRequest(config)config.cancelToken new CancelToken(c {queue.push({url: config.url,method: config.method,params: config.params,data: config.data,cancel: c,})})return config},error {return Promise.reject(error)} )// 响应拦截器 service.interceptors.response.use((response: AxiosResponse): any {removeRepeatRequest(response.config)return Promise.resolve(response)},error {return Promise.reject(error)} )export default service2、发布订阅方式 灵感来源 前端接口防止重复请求实现方案 /** Author: LYM* Date: 2024-03-28 14:12:54* LastEditors: LYM* LastEditTime: 2024-03-28 14:56:44* Description: 封装axios*/ import { gMessageError, gMessageWarning, gMessageSuccess } from /plugins/naiveMessage import type { AxiosRequestConfig, AxiosResponse } from axios import axios from axios import { ContentTypeEnum } from ./httpEnum import { checkResponseHttpStatus, loginStatusExpiresHandler } from ./statusHandler import type { IRequestOptions, IResult } from ./typesconst baseURL import.meta.env.VITE_USER_BASE_URLlet isRefreshing: boolean false let retryRequests: any[] []// 发布订阅 class EventEmitter {[x: string]: {}constructor() {this.event {}}on(type: string | number, cbres: any, cbrej: any) {if (!this.event[type]) {this.event[type] [[cbres, cbrej]]} else {this.event[type].push([cbres, cbrej])}}emit(type: string | number, res: any, ansType: string) {if (!this.event[type]) returnelse {this.event[type].forEach((cbArr: ((arg0: any) void)[]) {if (ansType resolve) {cbArr[0](res)} else {cbArr[1](res)}})}} }// 根据请求生成对应的key const generateReqKey (config: { method: string; url: string; params: string; data: string },hash: string ) {const { method, url, params, data } configreturn [method, url, JSON.stringify(params), JSON.stringify(data), hash].join() }// 判断是否为上传请求 const isFileUploadApi (config: { data: any }) {return Object.prototype.toString.call(config.data) [object FormData] }// 存储已发送但未响应的请求 const pendingRequest new Set() // 发布订阅容器 const ev new EventEmitter()const service axios.create({baseURL: import.meta.env.VITE_BASE_URL,timeout: 10 * 60 * 1000,headers: {Content-Type: ContentTypeEnum.FORM_URLENCODED,}, })// 请求拦截器 service.interceptors.request.use(async (config: any) {const hash location.hash// 生成请求Keyconst reqKey generateReqKey(config, hash)if (!isFileUploadApi(config) pendingRequest.has(reqKey)) {// 如果是相同请求,在这里将请求挂起通过发布订阅来为该请求返回结果// 这里需注意拿到结果后无论成功与否都需要return Promise.reject()来中断这次请求否则请求会正常发送至服务器let res nulltry {// 接口成功响应res await new Promise((resolve, reject) {ev.on(reqKey, resolve, reject)})return Promise.reject({type: limitResSuccess,val: res,})} catch (limitFunErr) {// 接口报错return Promise.reject({type: limitResError,val: limitFunErr,})}} else {// 将请求的key保存在configconfig.pendKey reqKeypendingRequest.add(reqKey)}return config},error {return Promise.reject(error)} )// 响应拦截器 service.interceptors.response.use((response: AxiosResponse): any {const res response.data || {}// 将拿到的结果发布给其他相同的接口handleSuccessResponse_limit(response)switch (res.code) {case 206:// 旧密码不正确breakcase 401:// 业务系统未登录调用login接口登录return loginStatusExpiresHandler(response, request, service)case 402:// 登录失败gMessageWarning({content: 登录失败请联系管理员,})breakcase 403:// 无权限跳转到无权限页面gMessageWarning({content: res.msg || 权限不足,})breakcase 404:// 获取csrfToken重新释放请求if (res.msg 丢失服务器端颁发的CSRFTOKEN ||res.msg 请求中请携带颁发的CSRFTOKEN) {if (!isRefreshing) {isRefreshing true// 请求tokenrequest({ url: /csrfToken, baseURL }).then((data: any) {if (data.code 200) {// 遍历缓存队列 发起请求 传入最新tokenretryRequests.forEach(cb cb())// 重试完清空这个队列retryRequests []}})}return new Promise(resolve {// 将resolve放进队列用一个函数形式来保存等token刷新后调用执行retryRequests.push(() {resolve(service(response.config))})})}breakcase 500:// 服务器错误gMessageError({content: 服务器错误请联系管理员,})return}return Promise.resolve(response)},error {const { code, message } errorif (code ECONNABORTED message.indexOf(timeout) ! -1) {gMessageError({content: 接口请求超时请刷新页面重试!,})return}const err JSON.stringify(error)if (err err.includes(Network Error)) {gMessageError({content: 网络异常请检查您的网络连接是否正常!,})return}// http 状态码提示信息处理const isCancel axios.isCancel(error)if (!isCancel) {checkResponseHttpStatus(error.response error.response.status, message)}return handleErrorResponse_limit(error)} )// 接口响应成功 const handleSuccessResponse_limit (response: any) {const reqKey response.config.pendKeyif (pendingRequest.has(reqKey)) {let x nulltry {x JSON.parse(JSON.stringify(response))} catch (e) {x response}pendingRequest.delete(reqKey)ev.emit(reqKey, x, resolve)delete ev.reqKey} }// 接口响应失败 const handleErrorResponse_limit (error: { type: string; val: any; config: { pendKey: any } }) {if (error.type error.type limitResSuccess) {return Promise.resolve(error.val)} else if (error.type error.type limitResError) {return Promise.reject(error.val)} else {const reqKey error.config.pendKeyif (pendingRequest.has(reqKey)) {let x nulltry {x JSON.parse(JSON.stringify(error))} catch (e) {x error}pendingRequest.delete(reqKey)ev.emit(reqKey, x, reject)delete ev.reqKey}}return Promise.reject(error) }export default serviceexport const request (config: AxiosRequestConfig, options?: IRequestOptions) {return new Promise((resolve, reject) {service(config).then((response: AxiosResponseIResult) {// 返回原始数据 包含http信息if (options?.isReturnNativeResponse) {resolve(response)}// 返回的接口信息const msg response.data.msg// 是否显示成功信息if (options?.isShowSuccessMessage) {gMessageSuccess({content: options.successMessageText ?? msg ?? 操作成功,})}if (options?.isShowErrorMessage) {gMessageError({content: options.errorMessageText ?? msg ?? 操作失败,})}resolve(response.data)}).catch(error {reject(error)})}) }httpEnum.ts /*** description: ContentType类型*/ export enum ContentTypeEnum {// jsonJSON application/json;charsetUTF-8,// jsonTEXT text/plain;charsetUTF-8,// form-data 一般配合qsFORM_URLENCODED application/x-www-form-urlencoded;charsetUTF-8,// form-data 上传FORM_DATA multipart/form-data;charsetUTF-8, }/*** description: 请求方法*/ export enum MethodEnum {GET GET,POST POST,PATCH PATCH,PUT PUT,DELETE DELETE, }naiveMessage.ts 基于naive-ui分装提示 /** Author: LYM* Date: 2023-03-28 08:47:39* LastEditors: LYM* LastEditTime: 2023-04-25 08:58:25* Description: naive message提示*/ import { createDiscreteApi, lightTheme, type ConfigProviderProps } from naive-ui import { computed } from vue import { IconWarningFill, IconInfoFill, IconCircleCloseFilled, IconSuccessFill } from /iconsconst configProviderPropsRef computedConfigProviderProps(() ({theme: lightTheme, }))const { message } createDiscreteApi([message], {configProviderProps: configProviderPropsRef, })// 警告 export const gMessageWarning (params?: any) {const {content 这是一条message warning信息,icon IconWarningFill,duration 5000,} params || {}message.warning(content, {icon: () h(icon, null),duration,}) }// 成功 export const gMessageSuccess (params?: any) {const {content 这是一条message success信息,icon IconSuccessFill,duration 5000,} params || {}message.success(content, {icon: () h(icon, null),duration,}) }// 失败 export const gMessageError (params?: any) {const {content 这是一条message error信息,icon IconCircleCloseFilled,duration 5000,} params || {}message.error(content, {icon: () h(icon, null),duration,}) }// 信息 export const gMessageInfo (params?: any) {const {content 这是一条message info信息,icon IconInfoFill,duration 5000,} params || {}message.info(content, {icon: () h(icon, null),duration,}) }// loading export const gMessageLoading (params?: any) {const { content 这是一条message Loading信息, duration 5000 } params || {}message.loading(content, {duration,}) }const gMessageObj {info: {icon: IconInfoFill,},warning: {icon: IconWarningFill,},success: {icon: IconSuccessFill,},error: {icon: IconCircleCloseFilled,}, }// 合并 export const gMessage (params?: any) {const { content 这是一条message信息, duration 5000, type info } params || {}message.create(content, {duration,type,icon: () h(gMessageObj[type], null),}) } checkResponseHttpStatus请求状态码收集处理---自行分装 loginStatusExpiresHandler登录过期或者token失效收集处理---自行分装 注意 心跳、轮询等请求可以在入参中透传随机key值解决
http://www.hkea.cn/news/14474962/

相关文章:

  • 天门市电子商务网站建设哪个网站可以建设网站
  • 丽江网站开发找千素网佛山本科网站建设
  • 中国手机最好的网站排名WordPress连接微博
  • linux 网站301济南电视台新闻频道
  • 网站建设手机端官网帝国网站怎么仿站
  • 单页网站如何做百度精简版入口
  • 深圳市住房和建设网站东莞计算机培训机构哪个最好
  • 北京企业官网网站建设哪家好论文中网站数据则呢做文献参考
  • 建设银行公积金网站提示udun百度人工优化
  • 网站建设的自查报告怎么在亚马逊做跨境电商
  • 珠海网站建设网百度广告代理公司
  • 无锡网站关键词优化wordpress安装模板后做
  • 有哪些做伦敦金的网站wordpress轻系统
  • 网站上的地图代码网站设计制作报价
  • 互联网网站如何做网站数据库访问
  • 上海的网站建设酒店如何做网络推广
  • wordpress固定连接白云怎样优化网站建设
  • 深圳做棋牌网站建设哪家公司收费合理英文网站建设口碑好
  • 广州市网站建设 乾图信息科技免费手机网站空间
  • 福州专业制作网站免费的企业品牌策划公司
  • 网站外链是友情连接吗百度技术培训中心
  • 笑傲网站建设江苏网站建设开发
  • 推广网站的方法有搜索引擎成立中英文网站建设工作领导小组
  • 高州市荷花镇网站建设网站建设流程简图
  • 网站开发背景图模板做网站推广员
  • 网站静态和动态寻花问柳-一个专做男人的网站
  • 上海成品网站网站制作价格上海
  • 企业营销型网站的内容wordpress打包小程序
  • jsp做物流网站免费做链接的网站吗
  • 家庭宽带做网站设计院