问题原因:
页面上曾经使用了一些背景图片,后续又将这些背景图片删除了,但是在资源中并没有删除,因此在资源迁移过程中还会继续搜索这个资源
解决方法:
进入相关页面编辑页,打开F12,进入页面样式,在浏览器开发者模式下控制台输入相关指令,保存退出就可以了
代码内容:
GD.registerFetchMiddleware(
'页面主题保存时验证并清理失效图片URL(优化版)',
async ({ body, url, method, headers }) => {
// 只拦截页面主题保存的请求
if (!url.includes('/api/page/theme/') || method !== 'POST') {
return { headers, body }
}
console.log('[图片URL验证] 开始处理请求:', url)
// URL 验证结果缓存(避免重复验证相同的 URL)
const urlValidationCache = new Map()
/**
* 验证图片 URL 是否有效
* @param {string} imageUrl - 图片 URL
* @returns {Promise<boolean>} - true 表示有效,false 表示失效
*/
async function validateImageUrl(imageUrl) {
if (!imageUrl || typeof imageUrl !== 'string') {
return false
}
// 检查缓存
if (urlValidationCache.has(imageUrl)) {
return urlValidationCache.get(imageUrl)
}
try {
// 构造完整的 URL(如果是相对路径)
const fullUrl = imageUrl.startsWith('http')
? imageUrl
: `${window.location.origin}${imageUrl}`
const response = await fetch(fullUrl, {
method: 'HEAD', // 使用 HEAD 方法,只获取响应头,不下载文件内容
cache: 'no-cache',
signal: AbortSignal.timeout(5000) // 5秒超时
})
const isValid = response.ok // 状态码 200-299 表示有效
// 缓存结果
urlValidationCache.set(imageUrl, isValid)
if (!isValid) {
console.log(`[图片URL验证] URL失效 (${response.status}):`, imageUrl)
}
return isValid
} catch (error) {
console.log('[图片URL验证] URL验证失败:', imageUrl, error.message)
// 验证失败视为 URL 无效
urlValidationCache.set(imageUrl, false)
return false
}
}
/**
* 构建对象路径字符串
* @param {Array} pathArray - 路径数组
* @returns {string} - 路径字符串
*/
function buildPathString(pathArray) {
let result = ''
for (let i = 0; i < pathArray.length; i++) {
const segment = pathArray
if (typeof segment === 'number') {
// 数组索引
result += `[${segment}]`
} else if (segment.startsWith('[')) {
// 特殊标记(如 [key=xxx])
result += segment
} else {
// 普通属性名
result += (i === 0 ? '' : '.') + segment
}
}
return result
}
/**
* 收集对象中所有需要验证的图片 URL
* @param {any} obj - 要处理的对象
* @param {Array} urlList - 收集到的 URL 列表
* @param {Array} path - 当前路径
*/
function collectImageUrls(obj, urlList = [], path = []) {
if (!obj || typeof obj !== 'object') {
return urlList
}
// 如果是数组,递归处理每个元素
if (Array.isArray(obj)) {
for (let i = 0; i < obj.length; i++) {
const item = obj
// 检查是否有特殊的标识字段(如 key, id 等)
let indexLabel = i
if (item && typeof item === 'object') {
if (item.key) {
indexLabel = `[key=${item.key}]`
} else if (item.id) {
indexLabel = `[id=${item.id}]`
} else if (item.cdId) {
indexLabel = `[cdId=${item.cdId}]`
} else if (item.tabId) {
indexLabel = `[tabId=${item.tabId}]`
} else if (item.i) {
indexLabel = `[i=${item.i}]`
}
}
collectImageUrls(item, urlList, [...path, indexLabel])
}
return urlList
}
// 检查当前对象是否是图片对象格式
const isImageObject =
obj.hasOwnProperty('url') &&
typeof obj.url === 'string' &&
obj.hasOwnProperty('sourceType') &&
obj.hasOwnProperty('renderType')
if (isImageObject && obj.url) {
urlList.push({
url: obj.url,
ref: obj, // 保存对象引用,方便后续删除 url 字段
path: buildPathString([...path, 'url']) // 保存完整路径
})
}
// 递归处理对象的所有属性
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
collectImageUrls(obj[key], urlList, [...path, key])
}
}
return urlList
}
/**
* 并发控制的 Promise 执行器
* @param {Array} tasks - 任务数组
* @param {number} concurrency - 并发数
* @returns {Promise<Array>} - 结果数组
*/
async function executeConcurrently(tasks, concurrency = 5) {
const results = []
const executing = []
for (const [index, task] of tasks.entries()) {
const promise = Promise.resolve().then(() => task()).then(result => {
results[index] = result
})
results.push(promise)
executing.push(promise)
if (executing.length >= concurrency) {
await Promise.race(executing)
executing.splice(executing.findIndex(p => p === promise), 1)
}
}
await Promise.all(results)
return results
}
try {
// 深拷贝 body 以避免修改原对象
const newBody = JSON.parse(JSON.stringify(body))
// 收集所有需要验证的图片 URL
const imageUrls = collectImageUrls(newBody)
if (imageUrls.length === 0) {
console.log('[图片URL验证] 未发现需要验证的图片URL')
return { headers, body: newBody }
}
console.log(`[图片URL验证] 发现 ${imageUrls.length} 个图片URL,开始验证...`)
// 创建验证任务
const validationTasks = imageUrls.map(({ url }) => {
return () => validateImageUrl(url)
})
// 并发执行验证(最多同时 5 个请求)
const validationResults = await executeConcurrently(validationTasks, 5)
// 删除失效的 URL 字段
let removedCount = 0
imageUrls.forEach(({ url, ref, path }, index) => {
if (!validationResults[index]) {
console.log('[图片URL验证] 删除失效URL:', url)
console.log('[图片URL验证] 路径位置:', path)
delete ref.url
removedCount++
}
})
console.log(`[图片URL验证] 处理完成,删除了 ${removedCount} 个失效URL`)
return { headers, body: newBody }
} catch (error) {
console.error('[图片URL验证] 处理过程出错:', error)
// 出错时返回原始 body
return { headers, body }
}
},
null,
100 // 优先级
)
console.log('[图片URL验证] 中间件已注册(优化版)')
|