将 refreshKey 调整为 signed URL 缓存版本号,同一路径同版本复用未过期签名地址。 让完整阿里云 OSS generated 地址在 hook 中先归一并走 read-url 换签。 补充前端回归测试,覆盖相同 refreshKey 不重复换签和完整 OSS 地址不裸写入图片。 更新运维文档与 Hermes 记忆,明确 refreshKey 不是每次绕过签名缓存。
73 lines
1.7 KiB
TypeScript
73 lines
1.7 KiB
TypeScript
import { useEffect, useState } from 'react';
|
||
|
||
import {
|
||
resolveAssetReadUrl,
|
||
shouldResolveAssetReadUrl,
|
||
} from '../services/assetReadUrlService';
|
||
|
||
type UseResolvedAssetReadUrlOptions = {
|
||
enabled?: boolean;
|
||
expireSeconds?: number;
|
||
refreshKey?: string | number | null;
|
||
};
|
||
|
||
export function useResolvedAssetReadUrl(
|
||
source: string | null | undefined,
|
||
options: UseResolvedAssetReadUrlOptions = {},
|
||
) {
|
||
const enabled = options.enabled !== false;
|
||
const normalizedSource = source?.trim() ?? '';
|
||
const shouldResolve =
|
||
enabled && shouldResolveAssetReadUrl(normalizedSource);
|
||
const [resolvedUrl, setResolvedUrl] = useState(
|
||
shouldResolve ? '' : normalizedSource,
|
||
);
|
||
|
||
useEffect(() => {
|
||
if (!normalizedSource) {
|
||
setResolvedUrl('');
|
||
return;
|
||
}
|
||
|
||
if (!shouldResolve) {
|
||
setResolvedUrl(normalizedSource);
|
||
return;
|
||
}
|
||
|
||
let cancelled = false;
|
||
// 生成资源通常是 OSS 私有对象;签名 URL 未就绪前不能把裸 generated 路径交给 img 触发无鉴权 GET。
|
||
setResolvedUrl('');
|
||
|
||
void resolveAssetReadUrl(normalizedSource, {
|
||
expireSeconds: options.expireSeconds,
|
||
refreshKey: options.refreshKey,
|
||
})
|
||
.then((nextUrl) => {
|
||
if (!cancelled) {
|
||
setResolvedUrl(nextUrl);
|
||
}
|
||
})
|
||
.catch(() => {
|
||
if (!cancelled) {
|
||
// 签名失败时保持空 src,避免继续请求无签名的私有对象兼容路径。
|
||
setResolvedUrl('');
|
||
}
|
||
});
|
||
|
||
return () => {
|
||
cancelled = true;
|
||
};
|
||
}, [
|
||
normalizedSource,
|
||
options.expireSeconds,
|
||
options.refreshKey,
|
||
shouldResolve,
|
||
]);
|
||
|
||
return {
|
||
resolvedUrl,
|
||
isResolving: shouldResolve && !resolvedUrl,
|
||
shouldResolve,
|
||
};
|
||
}
|