PHP $_SESSION 数组在前端生产构建时为空,但在开发构建时不是

Posted

技术标签:

【中文标题】PHP $_SESSION 数组在前端生产构建时为空,但在开发构建时不是【英文标题】:PHP $_SESSION array is empty with frontend production build but NOT with developement build 【发布时间】:2021-12-10 09:35:30 【问题描述】:

我有一个托管在 https://api.mydomain.abc 的后端,我正在开发一个使用 webpack 服务器的 vue/quasar CLI 前端。

当前端在开发模式下运行时,它由 webpack 网络服务器托管,前端代码中的 url 为 /api/index.php 格式。然后将 webpack 服务器配置为将它们代理到真正的后端 url:

devServer: 
  ...,
  proxy: 
    // proxy all requests starting with /api to avoid cors problems.
    '/api': 
      target: 'https://api.mydomain.abc',
      changeOrigin: true,
      pathRewrite: 
        '^/api': '' //remove /api from the final url
      
    
  
,

在生产模式下运行时,前端由位于 https://www.mydomain.abcnginx 服务器托管,前端的 URL 现在直接类似于 https://api.mydomain.abc

从现在开始,两种请求类型(开发和生产)都是相同的。 https://api.mydomain.abc 请求被同一个 NGINX 服务器监听,但现在作为反向代理工作,将它们重定向到带有 PHP 模块的 apache 服务器。这里有一个非常简单的纯 PHP 脚本,没有任何外部框架或库,它只是管理登录并在用户正确登录时从数据库返回一些动态值。

关键是在开发环境中一切正常,但在生产环境中,所有受登录保护的请求都失败了,因为 $_SESSION 数组为空!!

我完全不知道是什么导致了这种错误,因为两种环境的后端都是一样的。

更多信息:

在 apache 服务器中设置了 CORS 标头以允许来自 www.mydomain.abc(以及 mydomain.abc)的请求,并且没有任何 CORS 错误。 两种环境都使用https 协议访问后端 我的 PHP 脚本在脚本开头无条件运行 session_start()

我尝试了this answer,但没有观察到任何变化。

什么可能导致两种环境之间出现这种差异?除了 webpack 服务器之外,它们实际上是相同的。

【问题讨论】:

仔细检查一下:你在 webpack 服务器中是否有指令来为生产服务器执行代理? 对不起@KenLee,我想我没有正确地理解你。当前端托管到生产 Web 服务器 (NGINX) 时,不涉及 Webpack 服务器。 NGINX 不处理会话。它用作前端的静态 Web 服务器(在生产模式下部署时)和 api Web 服务器 (apache) 的反向代理。 apache 是管理会话的那个吗?关键是这两个环境(开发和产品)都是一样的,都共享相同的反向代理和相同的后端环境。唯一的区别是,在开发模式下,在一切之上还有另一个代理,即 webpack 服务器,它以某种方式使其与众不同。 嗯,这是从服务器发送到客户端的Set-Cookie 标头。应该从客户端发送到服务器的Cookie: 标头呢? @vstm 是的,就是这样。 credentials: "include"fetch 成功。在开发过程中没有触发该问题,因为它是前端和后端之间的same-origin 环境,而不是cross-origin。还很高兴注意到标头 Access-Control-Allow-Credentials: "true" 也需要设置到服务器端,如果不是 CORS 再次咬人的话。谢谢大家的帮助。如果你愿意,你可以回答,我会选择它。 【参考方案1】:

我会自己回答。问题在于,在开发过程中,浏览器位于 localhost url 中,向 localhost 服务器发出请求(webpack 服务器,然后将其代理到真正的 api 生产服务器,但浏览器不知道这一点)。这是浏览器的same-origin 环境,因此fetch API 将凭据(phpsessioncookie)发送到服务器,因为这是same-origin 环境中的默认行为。

在生产环境中,webpack 服务器不参与其中,浏览器在(www.)mydomain.comapi.mydomain.com 发出请求。这里的问题是,即使 (www.)mydomain.com 在 API Web 服务器中被设置为允许的来源,对于浏览器来说,它是一个 cross-origin 环境,这意味着 fetch API 默认不发送凭据。 credentials:include 覆盖默认值并发送它们。

如果不存在,服务器端也需要标头Access-Control-Allow-Credentials: "true"

【讨论】:

以上是关于PHP $_SESSION 数组在前端生产构建时为空,但在开发构建时不是的主要内容,如果未能解决你的问题,请参考以下文章

如何取消设置 PHP 中作为数组的 _SESSION 变量

16_构建memcached服务LNMP+memcachedPHP的本地Session信息PHP实现session共享

如何在 PHP 中取消设置会话数组

一次为多个用户提供 PHP $_SESSION

PHP执行Session与前端JS之间的关系

前端PHP Session的实例