fix: normalize overseas PDA API paths
This commit is contained in:
+11
-10
@@ -40,10 +40,19 @@ async function tokenAfterUnauthorized(failedToken) {
|
||||
return refreshOverseasToken()
|
||||
}
|
||||
|
||||
function overseasUrl(path) {
|
||||
const base = String(session.apiBase || '').replace(/\/$/, '')
|
||||
const value = `/${String(path || '').replace(/^\/+/, '')}`
|
||||
const normalized = /\/(?:api|overseas-api)$/.test(base)
|
||||
? value.replace(/^\/api(?=\/)/, '')
|
||||
: value
|
||||
return `${base}${normalized}`
|
||||
}
|
||||
|
||||
function rawRequest(method, path, data, token) {
|
||||
return new Promise((resolve, reject) => {
|
||||
uni.request({
|
||||
url: `${session.apiBase}${path}`,
|
||||
url: overseasUrl(path),
|
||||
method,
|
||||
data,
|
||||
header: { Accept: 'application/json', Authorization: `Bearer ${token}` },
|
||||
@@ -72,7 +81,7 @@ export async function overseasRequest(method, path, data, retry = true) {
|
||||
function rawUpload(path, filePath, name, token) {
|
||||
return new Promise((resolve, reject) => {
|
||||
uni.uploadFile({
|
||||
url: `${session.apiBase}${path}`,
|
||||
url: overseasUrl(path),
|
||||
filePath,
|
||||
name,
|
||||
header: { Authorization: `Bearer ${token}` },
|
||||
@@ -82,14 +91,6 @@ function rawUpload(path, filePath, name, token) {
|
||||
})
|
||||
}
|
||||
|
||||
function overseasUrl(path) {
|
||||
const value = String(path || '')
|
||||
const normalized = /\/(?:api|overseas-api)$/.test(session.apiBase)
|
||||
? value.replace(/^\/api(?=\/)/, '')
|
||||
: value
|
||||
return `${session.apiBase}${normalized}`
|
||||
}
|
||||
|
||||
function rawDownload(path, token) {
|
||||
return new Promise((resolve, reject) => {
|
||||
uni.downloadFile({
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
import { overseasRequest } from './overseas.js'
|
||||
|
||||
const BASE = '/api/pda/v1/last-leg/pallet-operations'
|
||||
const BASE = '/pda/v1/last-leg/pallet-operations'
|
||||
|
||||
export function resolvePallet(code) {
|
||||
return overseasRequest('POST', `${BASE}/pallets/resolve`, { code: String(code || '').trim() })
|
||||
|
||||
@@ -2,6 +2,7 @@ import test from 'node:test'
|
||||
import assert from 'node:assert/strict'
|
||||
|
||||
import { overseasDownload, overseasRequest, overseasUpload, resetOverseasRequestStateForTest } from '../src/api/overseas.js'
|
||||
import { resolvePallet } from '../src/api/pallet.js'
|
||||
import { PDA_AUTHORITY, PDA_ROLE, session, signInWithTokens, signOut } from '../src/stores/session.js'
|
||||
|
||||
const future = () => Math.floor(Date.now() / 1000) + 3600
|
||||
@@ -34,6 +35,38 @@ const denied = (requestId = 'request-401', traceId = 'trace-401') => ({
|
||||
statusCode: 401, data: { code: 'A0401', message: 'expired', requestId, traceId }, header: {}
|
||||
})
|
||||
|
||||
test('H5 proxy and App API roots normalize request upload and download paths to one public api prefix', async () => {
|
||||
prepareSession()
|
||||
const requests = []; const uploads = []; const downloads = []
|
||||
globalThis.uni.request = (options) => { requests.push(options.url); options.success(ok({ palletCode: 'PLT-1' })) }
|
||||
globalThis.uni.uploadFile = (options) => { uploads.push(options.url); options.success({ statusCode: 200, data: JSON.stringify({ code: '200', data: { fileId: '1' } }), header: {} }) }
|
||||
globalThis.uni.downloadFile = (options) => { downloads.push(options.url); options.success({ statusCode: 200, tempFilePath: '/tmp/photo.jpg', header: {} }) }
|
||||
|
||||
session.apiBase = '/overseas-api'
|
||||
await resolvePallet('PLT-1')
|
||||
await overseasUpload('/api/pda/v1/last-leg/photos/files', '/tmp/photo.jpg')
|
||||
await overseasDownload('/api/pda/v1/last-leg/photos/files/1/download')
|
||||
|
||||
session.apiBase = 'https://overseas.example.com/api/'
|
||||
await resolvePallet('PLT-1')
|
||||
await overseasUpload('/api/pda/v1/last-leg/photos/files', '/tmp/photo.jpg')
|
||||
await overseasDownload('/api/pda/v1/last-leg/photos/files/1/download')
|
||||
|
||||
assert.deepEqual(requests, [
|
||||
'/overseas-api/pda/v1/last-leg/pallet-operations/pallets/resolve',
|
||||
'https://overseas.example.com/api/pda/v1/last-leg/pallet-operations/pallets/resolve'
|
||||
])
|
||||
assert.deepEqual(uploads, [
|
||||
'/overseas-api/pda/v1/last-leg/photos/files',
|
||||
'https://overseas.example.com/api/pda/v1/last-leg/photos/files'
|
||||
])
|
||||
assert.deepEqual(downloads, [
|
||||
'/overseas-api/pda/v1/last-leg/photos/files/1/download',
|
||||
'https://overseas.example.com/api/pda/v1/last-leg/photos/files/1/download'
|
||||
])
|
||||
for (const url of [...requests, ...uploads, ...downloads]) assert.doesNotMatch(url, /\/api\/api\//)
|
||||
})
|
||||
|
||||
test('concurrent old-token 401 responses share one refresh and each replay once with the atomically replaced token', async () => {
|
||||
const old = prepareSession(); const next = tokens('new')
|
||||
let refreshCount = 0; let oldCalls = 0; let newCalls = 0
|
||||
|
||||
@@ -21,6 +21,8 @@ test('pallet API maps only the frozen overseas PDA operation endpoints', async (
|
||||
assert.match(api, new RegExp(path.replace('/', '\\/')))
|
||||
}
|
||||
assert.match(api, /overseasRequest/)
|
||||
assert.match(api, /const BASE = '\/pda\/v1\/last-leg\/pallet-operations'/)
|
||||
assert.doesNotMatch(api, /const BASE = '\/api\/pda/)
|
||||
for (const forbidden of ['customerId', 'warehouseId', 'locationId']) assert.doesNotMatch(api, new RegExp(forbidden))
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user