Playwright:认证数据无法从state文件传递至上下文致401错误
问题:Playwright存储会话状态后请求返回401错误
我编写了注册并认证用户的函数,将storageState数据保存至state.json文件,每个测试前调用该函数,文件已成功写入数据,但使用该文件的会话数据发起请求时却返回401错误。手动在请求头指定Token可正常返回200状态码。
函数代码
import { request } from "@playwright/test"; import { API_URL} from "../utils/constants" export const getRequest = async () => request.newContext({ baseURL: API_URL, storageState: 'state.json' }); export function randomString(length) { let result = ''; const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; const charactersLength = characters.length; let counter = 0; while (counter < length) { result += characters.charAt(Math.floor(Math.random() * charactersLength)); counter += 1; } return result; } export async function createUser(){ let request = await getRequest(); const randomName = `test${randomString(5)}`; const randomLastName = `test${randomString(5)}`; const randomEmail = `${randomString(5)}@${randomString(3)}.com`; const randomPassword = `${randomString(8)}`; const body = { firstName: randomName, lastName: randomLastName, email: randomEmail, password: randomPassword } const response = await request.post( '/users', { data: body, } ); const bodyLogin = { email: randomEmail, password: randomPassword } const responseLogin = await request.post( '/users/login', { data:bodyLogin } ) await request.storageState({ path: 'state.json' }); }
测试代码
import { test, expect } from '@playwright/test'; import { getRequest } from '../../common/user'; import { randomString } from '../../common/user'; import { createUser } from '../../common/user'; test.beforeEach(async() => { await createUser(); }) test('Should create a user', async () => { let request = await getRequest(); const response = await request.get('/contacts'); const answer = response.body(); await expect(response.status()).toEqual(200) });
手动指定Token可正常请求的示例
const response = await request.get('/contacts', { headers: { Authorization: "eyJhbGciOiJIU" } });
问题原因
- 上下文加载时机错误:
createUser中调用getRequest()创建请求上下文时,会提前加载当时还未更新的state.json(甚至可能是空文件),后续登录后的会话状态无法关联到这个上下文。 - StorageState默认不存储自定义Header:Playwright的
storageState默认仅存储Cookie,而你的API使用Authorization头携带Token,这种认证信息不会被自动存入storageState。
解决方案
步骤1:修改createUser函数,正确捕获并存储Token
直接创建全新的请求上下文,避免提前加载旧的state文件,同时从登录响应中提取Token并手动写入storageState的请求头:
import { request } from "@playwright/test"; import { API_URL} from "../utils/constants" // 保留randomString函数不变 export function randomString(length) { let result = ''; const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; const charactersLength = characters.length; let counter = 0; while (counter < length) { result += characters.charAt(Math.floor(Math.random() * charactersLength)); counter += 1; } return result; } export async function createUser(){ // 创建全新的请求上下文,不加载现有state.json const requestCtx = await request.newContext({ baseURL: API_URL }); const randomName = `test${randomString(5)}`; const randomLastName = `test${randomString(5)}`; const randomEmail = `${randomString(5)}@${randomString(3)}.com`; const randomPassword = `${randomString(8)}`; // 注册用户 await requestCtx.post('/users', { data: { firstName: randomName, lastName: randomLastName, email: randomEmail, password: randomPassword } }); // 用户登录并获取Token const loginResponse = await requestCtx.post('/users/login', { data: { email: randomEmail, password: randomPassword } }); const loginData = await loginResponse.json(); // 注意:根据API文档确认Token字段名,可能是token/access_token const authToken = loginData.token; // 手动构建包含Authorization头的storageState await requestCtx.storageState({ path: 'state.json', additionalHttpHeaders: { Authorization: `Bearer ${authToken}` } }); // 销毁上下文 await requestCtx.dispose(); } // 保留getRequest函数不变 export const getRequest = async () => request.newContext({ baseURL: API_URL, storageState: 'state.json' });
步骤2:验证state.json内容
执行createUser后,打开state.json确认是否包含additionalHttpHeaders字段,示例如下:
{ "cookies": [], "origins": [], "additionalHttpHeaders": { "Authorization": "Bearer eyJhbGciOiJIU..." } }
步骤3:保持测试代码不变
原测试代码无需修改,beforeEach中调用createUser后,getRequest()会加载包含正确Authorization头的state.json,请求即可正常通过认证。
内容的提问来源于stack exchange,提问作者newgavici
相关产品推荐
相关产品推荐

