|
|
@@ -79,6 +79,43 @@ export class FetchClient {
|
|
|
return 'download'
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 处理下载类请求的非 2xx 响应。
|
|
|
+ *
|
|
|
+ * download/downloadToBlob 不像 request() 那样自动经过响应拦截器,
|
|
|
+ * 导致 401/403 时不会触发刷新 Token / 跳转登录。这里补齐这一行为:
|
|
|
+ * 把非 ok 响应构造成 FetchResponse 交给响应拦截器处理(触发刷新/跳转),
|
|
|
+ * 无论拦截器是否抛错,最终都以下载失败错误结束(下载无法用重放结果续流)。
|
|
|
+ */
|
|
|
+ private async handleDownloadNotOk(res: globalThis.Response): Promise<never> {
|
|
|
+ const contentType = res.headers.get('Content-Type') || ''
|
|
|
+ const data = contentType.includes('application/json') ? await res.json() : await res.text()
|
|
|
+
|
|
|
+ const result: FetchResponse<any> = {
|
|
|
+ status: res.status,
|
|
|
+ ok: false,
|
|
|
+ data: typeof data === 'string' ? data : JSON.stringify(data),
|
|
|
+ // 下载请求无法安全重放为流,这里提供一个占位 retry,
|
|
|
+ // 让拦截器识别为「可刷新」的请求并触发刷新/跳转逻辑。
|
|
|
+ retry: async () => ({
|
|
|
+ status: res.status,
|
|
|
+ ok: false,
|
|
|
+ data: typeof data === 'string' ? data : JSON.stringify(data),
|
|
|
+ }),
|
|
|
+ }
|
|
|
+
|
|
|
+ if (this.responseInterceptor) {
|
|
|
+ try {
|
|
|
+ await this.responseInterceptor(result)
|
|
|
+ } catch (err) {
|
|
|
+ // 拦截器已处理(如刷新失败并跳转登录),继续抛出下载失败错误
|
|
|
+ console.warn('Download interceptor handled error:', err)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ throw new Error(`Download failed with status ${res.status}`)
|
|
|
+ }
|
|
|
+
|
|
|
async request<D = any>(
|
|
|
url: string,
|
|
|
method: HttpMethod = 'GET',
|
|
|
@@ -254,9 +291,7 @@ export class FetchClient {
|
|
|
|
|
|
// 发起请求
|
|
|
const res = await fetch(fullURL, finalConfig)
|
|
|
- if (!res.ok) {
|
|
|
- throw new Error(`Download failed with status ${res.status}`)
|
|
|
- }
|
|
|
+ if (!res.ok) { await this.handleDownloadNotOk(res) }
|
|
|
|
|
|
// 尝试从后端 header 获取文件名
|
|
|
let downloadName = filename
|
|
|
@@ -337,9 +372,7 @@ export class FetchClient {
|
|
|
|
|
|
// 发起请求
|
|
|
const res = await fetch(fullURL, finalConfig)
|
|
|
- if (!res.ok) {
|
|
|
- throw new Error(`Download failed with status ${res.status}`)
|
|
|
- }
|
|
|
+ if (!res.ok) { await this.handleDownloadNotOk(res) }
|
|
|
|
|
|
if (!res.body) throw new Error('No response body')
|
|
|
|