refactor(web): update service clients
- services/agentAssets.js: update agent assets service client - services/api.js: update API service client - services/employees.js: update employees service client
This commit is contained in:
@@ -1,37 +1,77 @@
|
||||
const API_BASE_STORAGE_KEY = 'x-financial-api-base-url'
|
||||
const AUTH_USER_STORAGE_KEY = 'x-financial-auth-user'
|
||||
|
||||
function readCurrentUserHeaders() {
|
||||
if (typeof window === 'undefined') {
|
||||
return {}
|
||||
}
|
||||
const API_BASE_STORAGE_KEY = 'x-financial-api-base-url'
|
||||
const AUTH_USER_STORAGE_KEY = 'x-financial-auth-user'
|
||||
|
||||
function isHeaderValueSafe(value) {
|
||||
const normalized = String(value || '').trim()
|
||||
if (!normalized) {
|
||||
return false
|
||||
}
|
||||
|
||||
for (let index = 0; index < normalized.length; index += 1) {
|
||||
const codePoint = normalized.charCodeAt(index)
|
||||
if (codePoint > 255 || codePoint === 10 || codePoint === 13 || codePoint === 0) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
export function pickSafeHeaderValue(value, fallback = '') {
|
||||
const normalized = String(value || '').trim()
|
||||
if (isHeaderValueSafe(normalized)) {
|
||||
return normalized
|
||||
}
|
||||
|
||||
const fallbackValue = String(fallback || '').trim()
|
||||
if (isHeaderValueSafe(fallbackValue)) {
|
||||
return fallbackValue
|
||||
}
|
||||
|
||||
return ''
|
||||
}
|
||||
|
||||
function readCurrentUserHeaders() {
|
||||
if (typeof window === 'undefined') {
|
||||
return {}
|
||||
}
|
||||
|
||||
const raw = window.sessionStorage.getItem(AUTH_USER_STORAGE_KEY)
|
||||
if (!raw) {
|
||||
return {}
|
||||
}
|
||||
|
||||
try {
|
||||
const payload = JSON.parse(raw)
|
||||
const username = String(payload?.username || '').trim()
|
||||
const name = String(payload?.name || username).trim()
|
||||
const roleCodes = Array.isArray(payload?.roleCodes) ? payload.roleCodes.filter(Boolean) : []
|
||||
const isAdmin = Boolean(payload?.isAdmin)
|
||||
|
||||
if (!username && !name) {
|
||||
return {}
|
||||
}
|
||||
|
||||
return {
|
||||
'x-auth-username': username,
|
||||
'x-auth-name': name,
|
||||
'x-auth-role-codes': roleCodes.join(','),
|
||||
'x-auth-is-admin': String(isAdmin)
|
||||
}
|
||||
} catch {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
try {
|
||||
const payload = JSON.parse(raw)
|
||||
const username = String(payload?.username || '').trim()
|
||||
const name = String(payload?.name || username).trim()
|
||||
const roleCodes = Array.isArray(payload?.roleCodes) ? payload.roleCodes.filter(Boolean) : []
|
||||
const isAdmin = Boolean(payload?.isAdmin)
|
||||
const safeUsername = pickSafeHeaderValue(username)
|
||||
const safeName = pickSafeHeaderValue(name)
|
||||
|
||||
if (!safeUsername && !safeName) {
|
||||
return {}
|
||||
}
|
||||
|
||||
const headers = {
|
||||
'x-auth-role-codes': roleCodes.join(','),
|
||||
'x-auth-is-admin': String(isAdmin)
|
||||
}
|
||||
|
||||
if (safeUsername) {
|
||||
headers['x-auth-username'] = safeUsername
|
||||
}
|
||||
|
||||
if (safeName) {
|
||||
headers['x-auth-name'] = safeName
|
||||
}
|
||||
|
||||
return headers
|
||||
} catch {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeApiBaseUrl(value) {
|
||||
return String(value || '/api/v1').replace(/\/$/, '')
|
||||
@@ -158,33 +198,60 @@ function resolveErrorMessage(payload, fallback = '接口请求失败,请稍后
|
||||
return fallback
|
||||
}
|
||||
|
||||
function sanitizeHeaders(headers) {
|
||||
const nextHeaders = {}
|
||||
|
||||
Object.entries(headers || {}).forEach(([key, value]) => {
|
||||
if (typeof value === 'undefined' || value === null) {
|
||||
return
|
||||
}
|
||||
|
||||
const normalizedValue = String(value).trim()
|
||||
if (!normalizedValue) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!isHeaderValueSafe(normalizedValue)) {
|
||||
return
|
||||
}
|
||||
|
||||
nextHeaders[key] = normalizedValue
|
||||
})
|
||||
|
||||
return nextHeaders
|
||||
}
|
||||
|
||||
export async function apiRequest(path, options = {}) {
|
||||
const {
|
||||
contentType = 'application/json',
|
||||
responseType = 'json',
|
||||
headers: customHeaders,
|
||||
headers: customHeaders,
|
||||
...fetchOptions
|
||||
} = options
|
||||
|
||||
const headers = {
|
||||
...readCurrentUserHeaders(),
|
||||
...(customHeaders || {})
|
||||
}
|
||||
|
||||
if (contentType !== null && typeof headers['Content-Type'] === 'undefined') {
|
||||
headers['Content-Type'] = contentType
|
||||
}
|
||||
const headers = sanitizeHeaders({
|
||||
...readCurrentUserHeaders(),
|
||||
...(customHeaders || {})
|
||||
})
|
||||
|
||||
if (contentType !== null && typeof headers['Content-Type'] === 'undefined') {
|
||||
headers['Content-Type'] = contentType
|
||||
}
|
||||
|
||||
let response
|
||||
|
||||
try {
|
||||
response = await fetch(buildUrl(path), {
|
||||
...fetchOptions,
|
||||
headers
|
||||
})
|
||||
} catch {
|
||||
throw new Error('无法连接 FastAPI 后端服务,请确认后端已启动且浏览器可访问后端端口。')
|
||||
}
|
||||
try {
|
||||
response = await fetch(buildUrl(path), {
|
||||
...fetchOptions,
|
||||
headers
|
||||
})
|
||||
} catch (error) {
|
||||
if (String(error?.message || '').includes('ByteString')) {
|
||||
throw new Error('当前登录用户信息包含浏览器不支持的请求头字符,请重新登录后重试。')
|
||||
}
|
||||
|
||||
throw new Error('无法连接 FastAPI 后端服务,请确认后端已启动且浏览器可访问后端端口。')
|
||||
}
|
||||
|
||||
if (responseType === 'blob') {
|
||||
if (!response.ok) {
|
||||
|
||||
Reference in New Issue
Block a user