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

登录后API调用无法保留PHP Session问题求助

问题:Axios在Cypress before:run事件中无法维持PHP会话状态

场景

本地运行的PHP应用,通过Cypress的before:run事件使用Axios调用API植入测试数据。已实现数据库植入方式,切换到API方式后遇到会话维持问题:登录API调用成功并返回PHPSESSID,但后续API调用未携带该会话ID,导致无法识别登录状态,无法执行需要权限的操作(如创建邀请)。

关键现象

  • 登录请求返回PHPSESSID=gp9329kmpfili2r49rl3hqc3no,但后续请求生成了新的PHPSESSID=00demprhj3anp6ketbvlkpo36e
  • 后续API返回{"PHP > logged in?": false},证明会话未关联

已尝试的方案

  • Axios配置:设置axios.defaults.withCredentials = true,添加请求/响应拦截器查看头信息
  • .htaccess配置CORS:允许跨域凭证、指定允许的Origin和头信息
  • PHP Session参数配置:设置secure=true、samesite=None等Cookie参数

额外解决方法

1. 复用Axios单例实例确保Cookie共享

Axios默认在同一个实例中维护Cookie,若静态方法调用时未复用实例,会导致Cookie丢失。修改ApiUtilities类使用单例Axios实例:

import axios from 'axios'

// 创建单例Axios实例并配置
const apiClient = axios.create({
  withCredentials: true,
  headers: {
    'Content-Type': 'application/json'
  }
})

apiClient.interceptors.request.use(
  (config) => {
    console.log('Sent headers:', config.headers)
    return config
  },
  (error) => Promise.reject(error)
)

export const enum ApiCallMethods {
  POST
}

export default class ApiUtilities {
  static async callApi(url: string, callMethod: ApiCallMethods, data: object): Promise<any> {
    let response
    try {
      switch (callMethod) {
        case ApiCallMethods.POST:
          response = await apiClient.post(url, data)
          break
      }
      console.log('Received headers:', response.headers)
      console.log('Data:', response.data)
      return response.data
    } catch (error) {
      throw error
    }
  }

  static async logIn() {
    await this.callApi('https://localhost/xyz/php/apis/users.php', ApiCallMethods.POST, {
      action: 'log_in',
      username: 'censored',
      password: 'censored'
    })
  }
}

2. 手动提取并携带PHPSESSID

若自动Cookie管理失效,手动从登录响应中提取PHPSESSID,后续请求通过Cookie头携带:

import axios from 'axios'

const apiClient = axios.create({
  withCredentials: true,
  headers: {
    'Content-Type': 'application/json'
  }
})

export const enum ApiCallMethods {
  POST
}

export default class ApiUtilities {
  private static sessionId: string | null = null

  static async logIn() {
    const response = await apiClient.post('https://localhost/xyz/php/apis/users.php', {
      action: 'log_in',
      username: 'censored',
      password: 'censored'
    })
    // 提取set-cookie中的PHPSESSID
    const setCookieHeader = response.headers['set-cookie']
    if (setCookieHeader) {
      const sessionCookie = setCookieHeader.find((cookie: string) => cookie.startsWith('PHPSESSID='))
      if (sessionCookie) {
        this.sessionId = sessionCookie.split(';')[0].split('=')[1]
      }
    }
    return response.data
  }

  static async callApi(url: string, callMethod: ApiCallMethods, data: object): Promise<any> {
    const config: any = {}
    if (this.sessionId) {
      config.headers = {
        Cookie: `PHPSESSID=${this.sessionId}`
      }
    }
    let response
    try {
      switch (callMethod) {
        case ApiCallMethods.POST:
          response = await apiClient.post(url, data, config)
          break
      }
      console.log('Received headers:', response.headers)
      console.log('Data:', response.data)
      return response.data
    } catch (error) {
      throw error
    }
  }
}

3. 使用tough-cookie手动管理Cookie Jar

Cypress的before:run运行在Node.js环境,Axios默认Cookie处理可能存在跨域问题,引入tough-cookie库手动管理:

import axios from 'axios'
import { CookieJar } from 'tough-cookie'
import { wrapper } from 'axios-cookiejar-support'

// 创建Cookie Jar并绑定到Axios实例
const cookieJar = new CookieJar()
const apiClient = wrapper(axios.create({
  withCredentials: true,
  jar: cookieJar,
  headers: {
    'Content-Type': 'application/json'
  }
}))

// 其余代码复用单例实例方案

4. 检查PHP会话存储目录权限

PHP会话默认存储在系统临时目录(如/tmp或Windows临时文件夹),若目录无读写权限,PHP无法保存会话文件,会每次生成新PHPSESSID。可在PHP中执行echo session_save_path();查看路径,确保Apache/PHP进程对该目录有读写权限。

5. 禁用本地HTTPS证书验证(仅测试用)

本地自签名HTTPS证书会被Node.js默认拒绝,导致Cookie无法存储。可在Axios实例中临时禁用SSL验证:

import axios from 'axios'
import https from 'https'

const apiClient = axios.create({
  withCredentials: true,
  httpsAgent: new https.Agent({
    rejectUnauthorized: false
  }),
  headers: {
    'Content-Type': 'application/json'
  }
})

注意:仅本地测试使用,生产环境绝对不能启用此配置

6. 检查Cypress全局Cookie清除配置

确认cypress.config.js中无experimentalSessionAndOrigin或clearCookiesBeforeRun等会提前清除Cookie的配置,避免影响会话维持。


内容的提问来源于stack exchange,提问作者Zuno

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 15:29:50