如何在Playwright apiContext中移除Authorization请求头?
问题描述
我将项目的Authorization实现为fixture,让所有测试模块都能以登录用户身份运行。现有一个S3文件上传功能,流程分为两步:
- 初始化上传:返回S3的
upload_url及其他信息; - 上传至S3:必须使用该
upload_url,且不允许携带Authorization请求头。
但上传时出现报错:
return (<Code>InvalidArgument</Code>Only one auth mechanism allowed; only the X-Amz-Algorithm query parameter, Signature query string parameter or the Authorization header should be specified )
我尝试在上传函数中将请求头设为空,但无效。请问该如何解决?是否必须使用browserContext并调用route()函数?
相关代码
测试函数代码
export const demandTags = async ( apiContext, campaign, campaignLinesDetails: CampaignLineResponse[], demandTagsDetails: DemandTagRequest[], use: (r: DemandTagResponse[]) => Promise<void>, ) => { const results: DemandTagResponse[] = []; // Get uploadCreative.mp4 from the files const filePromise = new Promise((resolve, reject) => { readFile('./uploadItems/uploadCreative.mp4', (err, data) => { if (err) { reject(err); } else { resolve(data); } }); }); // eslint-disable-next-line @typescript-eslint/no-explicit-any const file: any = await filePromise; // Initiate upload const initiateUpload = await apiContext.post('/api/demandtag/initiate_upload/', { data: { file_name: 'uploadCreative.mp4', file_type: 'video/mp4', file_size: file.length, } as apiTypes.UploadRequest, }); await expect(initiateUpload).toBeOK(); const responseJSONinitiateUpload = await initiateUpload.json(); expect(responseJSONinitiateUpload.parts[0].offset).toBe(0); expect(responseJSONinitiateUpload.parts[0].limit).toBe(file.length); expect(responseJSONinitiateUpload.parts).toHaveLength(1); // Upload the part const partResponse = await apiContext.put(responseJSONinitiateUpload.parts[0].url, { headers: { // 'Content-Type': '', }, data: file, }); await expect(partResponse).toBeOK(); const etag = await partResponse.headers()['etag']; const completeUpload = await apiContext.post('/api/demandtag/complete_upload/', { data: { upload_token: responseJSONinitiateUpload.upload_token, etags: [etag], } as apiTypes.CompleteUploadRequest, }); await expect(completeUpload).toBeOK(); const responseJSONcompleteUpload = await completeUpload.json(); // Create demand tag for (const demandTagDetails of demandTagsDetails) { const createDemandTag = await apiContext.post('/api/demandtag/', { data: { name: demandTagDetails.name, budget_value: demandTagDetails.budgetValue, campaign_line: campaignLinesDetails[0].id, pixel_url: demandTagDetails.pixelUrl, creative_landing_page_url: demandTagDetails.creativeLandingPageUrl, creative_s3: responseJSONcompleteUpload.url, creative_slug: demandTagDetails.creativeSlug, start_date: demandTagDetails.startDate, end_date: demandTagDetails.endDate, } as apiTypes.DemandTagRequest, }); await expect(createDemandTag).toBeOK(); results.push({ ...demandTagDetails, id: (await createDemandTag.json()).id }); } await use(results); // Delete created demand tags for (const demandTag of results) { const responseDelete = await apiContext.delete(`/api/demandtag/${demandTag.id}/`); expect([204, 404]).toContain(responseDelete.status()); } };
Fixture定义代码
export const test = base.extend<TestFixtures, WorkerFixtures>({ authToken: async ({ request }, use) => { await authToken(request, use); }, apiContext: async ({ authToken }, use) => { await use( await request.newContext({ baseURL: `${process.env.PROTOCOL!}://${process.env.HOST!}:${process.env.PORT!}`, extraHTTPHeaders: { authorization: `Token ${authToken}`, }, }), ); }, staticUrl: [ async ({}, use) => { await staticUrlFixture(use); }, { scope: 'worker' }, ], });
解决方案
不需要使用browserContext的route()函数,有两种更简单的解决方式:
方法一:显式移除Authorization头
当前的apiContext全局携带了Authorization头,直接设置headers为空字符串不会覆盖全局头,必须显式将authorization设为undefined,这样会移除全局的对应请求头:
修改上传部分的代码:
// Upload the part const partResponse = await apiContext.put(responseJSONinitiateUpload.parts[0].url, { headers: { authorization: undefined, // 显式移除全局Authorization头 'Content-Type': 'video/mp4', // 根据文件类型设置正确的Content-Type }, data: file, }); await expect(partResponse).toBeOK();
方法二:创建不带Auth头的独立API上下文
如果需要多次发起无Auth的请求,可以创建一个临时的、不带额外HTTP头的API上下文:
// 创建临时API上下文(无全局Auth头) const s3ApiContext = await request.newContext(); // Upload the part const partResponse = await s3ApiContext.put(responseJSONinitiateUpload.parts[0].url, { headers: { 'Content-Type': 'video/mp4', }, data: file, }); await expect(partResponse).toBeOK(); // 可选:请求完成后销毁上下文 await s3ApiContext.dispose();
为什么之前设空无效?
Playwright的API上下文会合并全局extraHTTPHeaders和请求级的headers:
- 如果请求级设置某个头为空字符串,全局的对应头仍会保留;
- 只有将请求级的头设为
undefined,才会完全移除该头。
内容的提问来源于stack exchange,提问作者jyang07
相关产品推荐
相关产品推荐

