You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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"
    }
}); 

问题原因

  1. 上下文加载时机错误:createUser中调用getRequest()创建请求上下文时,会提前加载当时还未更新的state.json(甚至可能是空文件),后续登录后的会话状态无法关联到这个上下文。
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 08:07:47