// 图片URL验证工具 /** * 验证图片URL是否有效 * @param {string} url - 图片URL * @returns {boolean} - 是否为有效图片URL */ function isValidImageUrl(url) { if (!url || typeof url !== 'string') { return false; } // 允许各种合法的图片URL格式 // 1. 标准HTTP/HTTPS URL if (url.startsWith('http://') || url.startsWith('https://')) { return true; } // 2. 阿里云OSS临时URL(可能包含特殊字符) if (url.includes('oss-cn-') && url.includes('aliyuncs.com')) { return true; } // 3. 小程序本地临时文件路径 if (url.startsWith('wxfile://')) { return true; } // 4. Base64编码的图片数据URL if (url.startsWith('data:image/')) { return true; } // 5. 占位符URL,在实际场景中会被替换 if (url.startsWith('placeholder://')) { return true; } return false; } /** * 过滤有效的图片URL * @param {Array} urls - 图片URL数组 * @returns {Array} - 有效的图片URL数组 */ function filterValidImageUrls(urls) { if (!Array.isArray(urls)) { return []; } return urls.filter(url => isValidImageUrl(url)); } /** * 修复商品对象中的图片URL * @param {Object} product - 商品对象 * @returns {Object} - 修复后的商品对象 */ function fixProductImageUrls(product) { if (!product || typeof product !== 'object') { return product; } // 创建商品的副本以避免直接修改原对象 const fixedProduct = { ...product }; // 修复主图片URL数组 if (fixedProduct.imageUrls && Array.isArray(fixedProduct.imageUrls)) { fixedProduct.imageUrls = filterValidImageUrls(fixedProduct.imageUrls); } // 修复备用图片URL数组(如果存在) if (fixedProduct.allImageUrls && Array.isArray(fixedProduct.allImageUrls)) { fixedProduct.allImageUrls = filterValidImageUrls(fixedProduct.allImageUrls); } // 修复单个图片URL(如果存在) if (fixedProduct.imageUrl && !isValidImageUrl(fixedProduct.imageUrl)) { fixedProduct.imageUrl = ''; } return fixedProduct; } /** * 修复商品列表中的图片URL * @param {Array} products - 商品列表 * @returns {Array} - 修复后的商品列表 */ function fixProductListImageUrls(products) { if (!Array.isArray(products)) { return products; } return products.map(product => fixProductImageUrls(product)); } /** * 标准化图片URL格式 * @param {string} url - 图片URL * @returns {string} - 标准化后的图片URL */ function normalizeImageUrl(url) { if (!url || typeof url !== 'string') { return ''; } // 去除URL前后的空格 const trimmedUrl = url.trim(); // 对于占位符URL,不进行任何额外处理,直接返回 if (trimmedUrl.startsWith('placeholder://')) { return trimmedUrl; } // 确保URL格式正确 if (trimmedUrl.startsWith('//')) { return 'https:' + trimmedUrl; } return trimmedUrl; } /** * 标准化图片URL数组 * @param {Array} urls - 图片URL数组 * @returns {Array} - 标准化后的图片URL数组 */ function normalizeImageUrls(urls) { if (!Array.isArray(urls)) { return []; } return urls.map(url => normalizeImageUrl(url)).filter(url => url !== ''); } /** * 获取图片URL验证统计信息 * @param {Array} urls - 图片URL数组 * @returns {Object} - 验证统计信息 */ function getImageUrlStats(urls) { const stats = { total: 0, valid: 0, invalid: 0, types: { http: 0, https: 0, oss: 0, wxfile: 0, data: 0, placeholder: 0, other: 0 } }; if (!Array.isArray(urls)) { return stats; } stats.total = urls.length; urls.forEach(url => { if (isValidImageUrl(url)) { stats.valid++; if (url.startsWith('http://')) { stats.types.http++; } else if (url.startsWith('https://')) { stats.types.https++; } else if (url.includes('oss-cn-') && url.includes('aliyuncs.com')) { stats.types.oss++; } else if (url.startsWith('wxfile://')) { stats.types.wxfile++; } else if (url.startsWith('data:image/')) { stats.types.data++; } else if (url.startsWith('uploaded_')) { stats.types.placeholder++; } else { stats.types.other++; } } else { stats.invalid++; } }); return stats; } module.exports = { isValidImageUrl, filterValidImageUrls, fixProductImageUrls, fixProductListImageUrls, normalizeImageUrl, normalizeImageUrls, getImageUrlStats };