我想使用 Jest + Supertest 通过 PUT 请求将文件上传到端点。
我有以下请求构造函数:
export async function uploadFileForJob(
uploadUrl: string,
accessToken: string,
filePath: string
) {
const upload_file_for_job = await request(uploadUrl)
.put("")
.set("Authorization", `Bearer ${accessToken}`)
.set("Content-Type", "model/gltf-binary")
.attach('file', filePath)
return upload_file_for_job;
}
以及测试文件本身中的请求:
const UploadFileForJob = await uploadFileForJob(
uploadUrl,
accessToken,
'C:/Job/Simulations/TestTshirt_04.glb'
);
expect(UploadFileForJob.status).toEqual(200);
端点总是向我返回 200 并且没有响应正文,因此我有另一种方法来检查文件是否确实正确上传:
export async function getJobView(jobId: string, accessToken: string) {
const get_job_view = await request(`https://${config.url}`)
.get(`/products-v0/_objects/${jobId}/Views/File`)
.set("Authorization", `Bearer ${accessToken}`)
.send();
return get_job_view;
}
const GetJobView = await getJobView(jobId, accessToken);
expect(GetJobView.status).toEqual(200);
expect(GetJobView.body.view).toBeTruthy();
在这里我已经收到 404 错误,这表明文件没有被先前的端点正确接受。我确信错误在于笑话如何采用我指向它的路线,并且任何变量中都没有错误,如果我与 Postman 使用相同的内容(使用二进制正文文件选择器),一切都会完美运行。正确的 .attach 应该怎样写?
终于找到解决办法了。有两个问题。 首先,上传文件需要一些时间,因此应该在文件上传完成后发送下一个请求,为此我使用了 do...while 循环,并进行了一些重试,检查文件最终是否已附加。
// Wait for the file to be attached to the job
let JobViewResponse;
const maxRetries = 20; // Number of retries before giving up
let retries = 0;
do {
// Introduce a small delay between each retry (e.g., 2 seconds)
await sleep(2000);
JobViewResponse = await getJobView(jobId, accessToken);
retries++;
} while (JobViewResponse.status !== 200 && retries < maxRetries);
// Check if the file is attached to the job
if (JobViewResponse.status === 200 && JobViewResponse.body.view) {
const viewData = JSON.parse(JobViewResponse.body.view);
expect(JobViewResponse.status).toEqual(200);
expect(JobViewResponse.body.view).toBeTruthy();
expect(viewData.Size).toBeGreaterThan(0);
console.log("File is attached to the job.");
} else {
console.error("File attachment to the job failed or took too long.");
}
第二个问题是 Attach() 尝试将文件作为多部分表单数据发送。但在我们的例子中,请求正文应该只包含原始字节。为了解决这个问题,我先使用 fs.readFileSync 读取内存中的文件。
export async function uploadFileForJob(
uploadUrl: string,
accessToken: string,
filePath: string
) {
const fileContents = fs.readFileSync(filePath);
const upload_file_for_job = await request(uploadUrl)
.put("")
.set("Authorization", `Bearer ${accessToken}`)
.set("Content-Type", "model/gltf-binary")
.send(fileContents);
return upload_file_for_job;
}