前言
在做某個(gè)需求時(shí)钠惩,將 token
存在了 SESSION
里族阅,然而呢篓跛,SESSION
是存在 Redis
里的坦刀。在檢查這個(gè) token
是否正確時(shí),卻發(fā)現(xiàn)鲤遥,時(shí)而正確,時(shí)而錯(cuò)誤渴频。
檢查了從 SESSION
里取出的值,發(fā)現(xiàn)里面的內(nèi)容會有幾率的不同卜朗。
于是咕村,查看了 Redis
里的值场钉,發(fā)現(xiàn)是存在懈涛,并且正確的逛万。查看了 /var/lib/php/sessions
里的值批钠,發(fā)現(xiàn)是存在,并且錯(cuò)誤的埋心。與之前打出的值一樣,這拷呆,我懵逼了疫粥。
于是漫長的 BUG
之路開始了。
原因
檢查了很久梗逮,還是不知原因,便請來了華仔(技術(shù)牛人)慷彤。
一開始,我們的方向是:因?yàn)榕渲玫膯栴}底哗,導(dǎo)致 Redis
讀的庫混亂了。檢查之后發(fā)現(xiàn)艘虎,配置沒有任何問題。
然后想到了野建,我的所有站點(diǎn)都在一個(gè)系統(tǒng)里,是不是因?yàn)槠渌军c(diǎn)引起的候生。試驗(yàn)之后發(fā)現(xiàn),果不其然唯鸭。
當(dāng)訪問了另外一個(gè)從文件讀取 SESSION
的站點(diǎn)之后,主站點(diǎn)就會取到兩種 Redis
目溉。
于是我就懷疑,是 PHP-FPM
的問題缭付,請求結(jié)束后,SESSION
并沒有被銷毀陷猫。
驗(yàn)證
在主站點(diǎn)的入口文件里,寫了一段代碼绣檬,主要是測試 SESSION
是否有被關(guān)閉嫂粟。
<?php
// ...
$status = session_status();
switch ($status) {
case PHP_SESSION_ACTIVE:
echo 'session is active';
break;
case PHP_SESSION_NONE:
case PHP_SESSION_DISABLED:
echo 'session is not active';
break;
}
exit();
// ...
檢測發(fā)現(xiàn)娇未,有幾率出現(xiàn) 'session is active' 的情況。這說明了官扣,次站點(diǎn)的請求結(jié)束后糊肠,并沒有關(guān)閉 SESSION
馍盟。 華仔看了一下源碼策菜,也證實(shí)了這件事情褥芒。
最終在 PHP
的官網(wǎng)上看到了這個(gè):
既然問題已經(jīng)出現(xiàn),那么锰扶,如何解決呢。
解決
次站點(diǎn)在響應(yīng)給出之前坷牛,先關(guān)閉 SESSION
,使用 session_write_close()
方法京闰。
同時(shí),主站點(diǎn)在初始化 SESSION
時(shí)蹂楣,可以先關(guān)閉 SESSION
再開啟,實(shí)現(xiàn)如下痊土。
<?php
// ...
$status = session_status();
switch ($status) {
case PHP_SESSION_ACTIVE:
session_write_close();
session_start();
break;
case PHP_SESSION_NONE:
case PHP_SESSION_DISABLED:
session_start();
break;
}
exit();
// ...
這個(gè)時(shí)候,就可以去自定義會話管理了赁酝,無論是存在 Redis
、Memcache
或者 database
里都可以酌呆。
總結(jié)
很多問題,在多數(shù)情況下肪笋,是不會出現(xiàn)的度迂。只有做多藤乙,才會錯(cuò)多惭墓。
然而,錯(cuò)并不可怕腊凶,發(fā)現(xiàn)并將其改正就好拴念。
-- EOF --
本文轉(zhuǎn)載自IMJCW
原文鏈接:PHP 兩個(gè)站點(diǎn)造成的SESSION混亂