From c6978c0983bc16cd26d40a46a9b1776deb8415b1 Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Tue, 15 Sep 2026 20:51:09 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/inbound.js | 4 ++-- src/api/overseas.js | 7 ++++++- src/api/relabel.js | 2 +- tests/overseas-request.test.mjs | 15 +++++++++++++++ 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/api/inbound.js b/src/api/inbound.js index 86c326a..1d22e16 100644 --- a/src/api/inbound.js +++ b/src/api/inbound.js @@ -17,8 +17,8 @@ export const getCurrentWarehouseProfile = () => { export const getReceivingContainer = async (containerNo) => normalizeReceivingSession(await overseasRequest('GET', `${RECEIVING_BASE}/${encodeURIComponent(containerNo)}`)) export const prepareReceivingContainer = async (containerNo, request) => normalizeReceivingSession(await overseasRequest('POST', `${RECEIVING_BASE}/${encodeURIComponent(containerNo)}/prepare`, request)) export const uploadCurrentUnloadPhoto = (filePath) => overseasUpload(current('/unload-photos/files'), filePath) -export const downloadCurrentUnloadPhoto = (downloadPath) => overseasDownload(downloadPath) -export const downloadCurrentDomesticLoadingPhoto = (downloadPath) => overseasDownload(downloadPath) +export const downloadCurrentUnloadPhoto = (downloadPath) => overseasDownload(downloadPath, { expectedContentTypePrefix: 'image/' }) +export const downloadCurrentDomesticLoadingPhoto = (downloadPath) => overseasDownload(downloadPath, { expectedContentTypePrefix: 'image/' }) export const signCurrentReceiving = async (request) => normalizeReceivingSession(await overseasRequest('POST', current('/sign'), request)) export const getCurrentReceiving = async () => normalizeReceivingSession(await overseasRequest('GET', current())) export const resolveCurrentCarton = async (cartonMark) => normalizeReceivingInbound(await overseasRequest('POST', current('/cartons/resolve'), { cartonMark })) diff --git a/src/api/overseas.js b/src/api/overseas.js index c792931..44d70df 100644 --- a/src/api/overseas.js +++ b/src/api/overseas.js @@ -116,7 +116,8 @@ export async function overseasUpload(path, filePath, name = 'file', retry = true return body.data } -export async function overseasDownload(path, retry = true) { +export async function overseasDownload(path, options = {}) { + const { retry = true, expectedContentTypePrefix = '' } = options const attemptedToken = session.token let response = await rawDownload(path, attemptedToken) if (retry && unauthorized(response)) { @@ -126,6 +127,10 @@ export async function overseasDownload(path, retry = true) { if (response?.statusCode !== 200 || !response?.tempFilePath) { throw errorFrom({ ...response, data: {} }, '签收照片下载失败') } + const contentType = String(response?.header?.['content-type'] || response?.header?.['Content-Type'] || '').toLowerCase() + if (expectedContentTypePrefix && !contentType.startsWith(expectedContentTypePrefix.toLowerCase())) { + throw errorFrom({ ...response, data: {} }, '照片服务返回了无效内容,请稍后重试') + } return response.tempFilePath } diff --git a/src/api/relabel.js b/src/api/relabel.js index b3312a8..d0d24f0 100644 --- a/src/api/relabel.js +++ b/src/api/relabel.js @@ -49,4 +49,4 @@ export const reportRelabelException = (relabelNo, request) => detailAction(relab export const completeRelabelTask = (relabelNo, request) => detailAction(relabelNo, '/complete', request) export const reviewRelabelTask = (relabelNo, request) => detailAction(relabelNo, '/review', request) export const uploadRelabelPhoto = (relabelNo, filePath) => overseasUpload(`${BASE}/${encoded(relabelNo)}/photos/files`, filePath) -export const downloadRelabelPhoto = (relabelNo, fileId) => overseasDownload(`${BASE}/${encoded(relabelNo)}/photos/files/${encoded(fileId)}/download`) +export const downloadRelabelPhoto = (relabelNo, fileId) => overseasDownload(`${BASE}/${encoded(relabelNo)}/photos/files/${encoded(fileId)}/download`, { expectedContentTypePrefix: 'image/' }) diff --git a/tests/overseas-request.test.mjs b/tests/overseas-request.test.mjs index a417d44..0a2a2ee 100644 --- a/tests/overseas-request.test.mjs +++ b/tests/overseas-request.test.mjs @@ -174,6 +174,21 @@ test('authenticated photo download maps the public api path through the H5 overs assert.equal(calls[0].header.Authorization, `Bearer ${value.overseasAccessToken}`) }) +test('image download rejects a JSON error envelope returned with HTTP 200', async () => { + prepareSession() + globalThis.uni.downloadFile = (options) => options.success({ + statusCode: 200, + tempFilePath: '/tmp/error.json', + header: { 'Content-Type': 'application/json', 'X-Request-Id': 'photo-request', 'X-Trace-Id': 'photo-trace' } + }) + + await assert.rejects( + overseasDownload('/api/pda/v1/last-leg/photo', { expectedContentTypePrefix: 'image/' }), + (error) => error.message === '照片服务返回了无效内容,请稍后重试' + && error.requestId === 'photo-request' && error.traceId === 'photo-trace' + ) +}) + test('business and network errors retain diagnostics without refreshing or clearing a valid session', async () => { prepareSession(); let refreshCount = 0 globalThis.uni.request = (options) => {