线上项目https看不了http的图片解决

解决方式:由后端转发,前端将图片url接口传给后端, 后端返回blob数据流展示,前端对图片url相同的进行缓存,不会重复发请求。

//封装方法utils/transitionImage.ts

js 复制代码
import { previewImage } from '@/api/common'
 
// 跟踪正在加载的URL
export const loadingUrls = new Set<string>()
// 跟踪pending状态的请求(用于取消请求)
const pendingRequests = new Map<string, AbortController()
// 记录每个URL的最新请求序列号(确保响应顺序正确)
const requestSequence = new Map<string, number>()
 
export const getImageUrl = async (
  url: string,
  pictureUrlsRef: { value: Record<string, string> },
  forceUpdate = false
): Promise<string | undefined> => {
  if (!url) return
 
  // 生成当前请求的序列号
  const currentSeq = (requestSequence.get(url) || 0) + 1
  requestSequence.set(url, currentSeq)
 
  // 强制刷新时:取消旧请求(如果存在)
  if (forceUpdate) {
    // 清除旧缓存
    if (pictureUrlsRef.value[url]) {
      URL.revokeObjectURL(pictureUrlsRef.value[url])
      delete pictureUrlsRef.value[url]
    }
 
    // 取消pending的旧请求
    const existingController = pendingRequests.get(url)
    if (existingController) {
      existingController.abort() // 中断旧请求
      pendingRequests.delete(url)
      loadingUrls.delete(url) // 移除加载中标记
    }
  } else {
    // 非强制刷新:如果已有缓存,直接返回(核心逻辑)
    if (pictureUrlsRef.value[url]) {
      return pictureUrlsRef.value[url]
    }
    // 非强制刷新:如果正在加载,直接返回(避免重复请求)
    if (loadingUrls.has(url)) {
      return
    }
  }
 
  // 发起新请求(仅当无缓存、非加载中、或强制刷新时)
  const controller = new AbortController()
  pendingRequests.set(url, controller)
  loadingUrls.add(url)
 
  try {
    const res = await previewImage(encodeURIComponent(url), {
      signal: controller.signal
    })
 
    // 校验序列号,确保只处理最新请求的响应
    if (currentSeq !== requestSequence.get(url)) {
      console.log(
        `忽略过期响应: ${url} (当前序列号: ${currentSeq}, 最新序列号: ${requestSequence.get(url)})`
      )
      return
    }
 
    if (res?.data instanceof Blob) {
      const blobUrl = URL.createObjectURL(res.data)
      pictureUrlsRef.value[url] = blobUrl // 缓存结果
      return blobUrl
    }
  } catch (error) {
    // 忽略主动取消的错误
    if ((error as Error).name !== 'AbortError') {
      console.error('图片加载失败:', error)
    }
  } finally {
    // 清理状态(仅当前请求是最新的才执行)
    if (currentSeq === requestSequence.get(url)) {
      loadingUrls.delete(url)
      pendingRequests.delete(url)
    }
  }
}
 
export const clearImageCache = (pictureUrlsRef: { value: Record<string, string> }) => {
  Object.values(pictureUrlsRef.value).forEach((url) => {
    if (url.startsWith('blob:')) {
      URL.revokeObjectURL(url)
    }
  })
  pictureUrlsRef.value = {}
  requestSequence.clear() // 重置序列号
}`

//vue页面内使用

js 复制代码
    
import { getImageUrl, loadingUrls, clearImageCache } from '@/utils/transitionImage'
 
 

const pictureUrls = ref<Record<string, string>>({})
 
 
const schema2 = reactive<DescriptionsSchema[]>([
{
    field: 'vehiclePicUri',
    label: '通行抓拍图',
    width: 100,
    slots: {
      default: (data: any) => {
        const imageUrl = data.vehiclePicUri
        const imgUrl = pictureUrls.value[imageUrl]
        const isLoading = Array.from(loadingUrls).includes(imageUrl)
        if (imageUrl && !imgUrl && !isLoading) {
          getImageUrl(imageUrl, pictureUrls)
        }
        return imgUrl ? (
          <ElImage
            style="width: 100px; height: 100px"
            src={imgUrl}
            zoom-rate={1.2}
            max-scale={7}
            min-scale={0.2}
            preview-src-list={[imgUrl]}
            initial-index={0}
            fit="cover"
          />
        ) : isLoading ? (
          <div class="flex items-center justify-center h-full">
            <i class="el-icon-loading"></i>
          </div>
        ) : (
          <div>(未知)</div>
        )
      }
    }
  }
])
 
 
 
// 监听弹窗打开,触发图片加载
watch(
  () => dialogVisible2.value,
  (newVal) => {
    if (newVal && data1) {
      const imageUrl = data1.vehiclePicUri
      if (imageUrl) {
        getImageUrl(imageUrl, pictureUrls)
      }
    }
  }
)
 
// 组件卸载时清理缓存,防止内存泄漏
onUnmounted(() => {
  clearImageCache(pictureUrls)
})
    
相关推荐
好好好明天会更好10 分钟前
vue中的this.$nextTick如何使用
前端·vue.js
我的div丢了肿么办11 分钟前
使用URLSearchParams 优雅的获取URL携带的参数
前端·javascript
XXXFIRE12 分钟前
微信小程序开发实战笔记:全流程梳理
前端·微信小程序
答案answer14 分钟前
回顾一下我的开源项目之路和Three.js 学习历程
前端·开源·three.js
ZoeLandia15 分钟前
nginx实战分析
运维·前端·nginx
张迅之啊15 分钟前
【React】MQTT + useEventBus 实现MQTT长连接以及消息分发
前端
入秋17 分钟前
【视觉震撼】我用Three.js让极光在网页里跳舞!
前端·three.js
盛夏绽放18 分钟前
Vue项目生产环境性能优化实战指南
前端·vue.js·性能优化
专注API从业者26 分钟前
Python/Node.js 调用taobao API:构建实时商品详情数据采集服务
大数据·前端·数据库·node.js
狂炫一碗大米饭1 小时前
Vue 3 的最佳开源分页库
前端·程序员·设计