CI / backend (push) Canceled after 0s
crypto.randomUUID() 与 navigator.clipboard 只在安全上下文(https / localhost)里存在,
生产入口是纯 http,于是:
- 所有 POST/PATCH/DELETE 在拼 Idempotency-Key 时直接抛 TypeError,
登录页只显示"登录失败",GET 一切正常,所以这个坑一直没暴露
- 「复制邀请链接」永远回"浏览器不允许自动复制"
改成幂等键自己拼一个 v4(getRandomValues 不受安全上下文限制,退回 Math.random),
复制走 navigator.clipboard → document.execCommand("copy") 两级降级。
顺带说明:这是生产上"能看不能写"的真正原因,不是权限或接口问题。
35 lines
1.0 KiB
TypeScript
35 lines
1.0 KiB
TypeScript
/**
|
||
* 复制文本。
|
||
*
|
||
* `navigator.clipboard` 只在**安全上下文**(https 或 localhost)里有,内网生产入口是
|
||
* 纯 http,那里它是 undefined——直接调会抛错,用户看到的却是"浏览器不允许自动复制"。
|
||
* 所以这里退回 `document.execCommand("copy")`:老,但在 http 下确实能用。
|
||
*/
|
||
export async function copyText(text: string): Promise<boolean> {
|
||
if (window.isSecureContext && navigator.clipboard?.writeText) {
|
||
try {
|
||
await navigator.clipboard.writeText(text);
|
||
return true;
|
||
} catch {
|
||
// 权限被拒也走兜底,别直接判定失败
|
||
}
|
||
}
|
||
|
||
const area = document.createElement("textarea");
|
||
area.value = text;
|
||
area.setAttribute("readonly", "");
|
||
area.style.position = "fixed";
|
||
area.style.top = "-1000px";
|
||
area.style.opacity = "0";
|
||
document.body.appendChild(area);
|
||
area.select();
|
||
let ok = false;
|
||
try {
|
||
ok = document.execCommand("copy");
|
||
} catch {
|
||
ok = false;
|
||
}
|
||
document.body.removeChild(area);
|
||
return ok;
|
||
}
|