From 2e5dd7d5133dc170274aa56287da4d980634c692 Mon Sep 17 00:00:00 2001 From: MaysWind Date: Sat, 27 Sep 2025 17:00:42 +0800 Subject: [PATCH] add content encoding to the response headers when the server returns js, csv or tsv --- cmd/webserver.go | 6 +++--- src/core/file.ts | 9 +++++++++ src/stores/user.ts | 9 ++++++--- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/cmd/webserver.go b/cmd/webserver.go index 3b71c298..9ae38f77 100644 --- a/cmd/webserver.go +++ b/cmd/webserver.go @@ -531,7 +531,7 @@ func bindCachedJs(fn core.DataHandlerFunc, store persistence.CacheStore) gin.Han if err != nil { utils.PrintDataErrorResult(c, "text/javascript", err) } else { - utils.PrintDataSuccessResult(c, "text/javascript", "", result) + utils.PrintDataSuccessResult(c, "text/javascript; charset=utf-8", "", result) } }) } @@ -544,7 +544,7 @@ func bindCsv(fn core.DataHandlerFunc) gin.HandlerFunc { if err != nil { utils.PrintDataErrorResult(c, "text/text", err) } else { - utils.PrintDataSuccessResult(c, "text/csv", fileName, result) + utils.PrintDataSuccessResult(c, "text/csv; charset=utf-8", fileName, result) } } } @@ -557,7 +557,7 @@ func bindTsv(fn core.DataHandlerFunc) gin.HandlerFunc { if err != nil { utils.PrintDataErrorResult(c, "text/text", err) } else { - utils.PrintDataSuccessResult(c, "text/tab-separated-values", fileName, result) + utils.PrintDataSuccessResult(c, "text/tab-separated-values; charset=utf-8", fileName, result) } } } diff --git a/src/core/file.ts b/src/core/file.ts index 51d9fcc4..cd7fc546 100644 --- a/src/core/file.ts +++ b/src/core/file.ts @@ -4,6 +4,7 @@ export class KnownFileType { public static readonly JSON = new KnownFileType('json', 'application/json'); public static readonly CSV = new KnownFileType('csv', 'text/csv'); public static readonly TSV = new KnownFileType('tsv', 'text/tab-separated-values'); + public static readonly TXT = new KnownFileType('txt', 'text/text'); public static readonly MARKDOWN = new KnownFileType('md', 'text/markdown'); public static readonly JS = new KnownFileType('js', 'application/javascript'); public static readonly JPG = new KnownFileType('jpg', 'image/jpeg'); @@ -18,6 +19,14 @@ export class KnownFileType { KnownFileType.allInstancesByExtension[extension] = this; } + public isSameType(contentType: string): boolean { + if (!contentType) { + return false; + } + + return this.contentType === contentType || contentType.indexOf(this.contentType) === 0; + } + public formatFileName(fileName: string): string { if (fileName.endsWith(`.${this.extension}`)) { return fileName; diff --git a/src/stores/user.ts b/src/stores/user.ts index a8a121ee..7b8a7dcb 100644 --- a/src/stores/user.ts +++ b/src/stores/user.ts @@ -5,6 +5,7 @@ import { useSettingsStore } from './setting.ts'; import { type WeekDayValue, WeekDay } from '@/core/datetime.ts'; import { FiscalYearStart } from '@/core/fiscalyear.ts'; +import { KnownFileType } from '@/core/file.ts'; import type { ApplicationCloudSetting } from '@/core/setting.ts'; import { @@ -380,10 +381,12 @@ export const useUserStore = defineStore('user', () => { return new Promise((resolve, reject) => { services.getExportedUserData(fileType, req).then(response => { if (response && response.headers) { - if (fileType === 'csv' && response.headers['content-type'] !== 'text/csv') { + const contentType = response.headers['content-type']?.toString() || ''; + + if (fileType === 'csv' && !KnownFileType.CSV.isSameType(contentType)) { reject({ message: 'Unable to retrieve exported user data' }); return; - } else if (fileType === 'tsv' && response.headers['content-type'] !== 'text/tab-separated-values') { + } else if (fileType === 'tsv' && !KnownFileType.TSV.isSameType(contentType)) { reject({ message: 'Unable to retrieve exported user data' }); return; } @@ -394,7 +397,7 @@ export const useUserStore = defineStore('user', () => { }).catch(error => { logger.error('failed to retrieve user statistics data', error); - if (error.response && error.response.headers['content-type'] === 'text/text' && error.response && error.response.data) { + if (error.response && KnownFileType.TXT.isSameType(error.response.headers['content-type']) && error.response && error.response.data) { reject({ message: 'error.' + error.response.data }); } else if (!error.processed) { reject({ message: 'Unable to retrieve exported user data' });