两次调用同一PHP脚本的fetch请求为何出现阻塞?
问题分析与解决
你的问题核心是浏览器的同URL请求排队机制,而非PHP会话锁的问题,具体原因和解决方法如下:
核心原因:浏览器的GET请求缓存优化
现代浏览器为了避免重复请求、利用缓存,会对同一域名下的相同URL的GET请求(fetch默认使用GET方法)进行串行排队处理——它会等待第一个请求完成后,再发送第二个请求,以此判断是否可以复用第一个请求的缓存结果。
即便你的PHP脚本已经通过session_write_close()释放了会话锁,服务器端已经可以处理并发请求,但浏览器这边直接把第二个请求按住了,导致它要等第一个请求完成后才会发送,最终总耗时变成20秒。
次要排查点:PHP会话锁的潜在问题(可能性低)
虽然你已经调用了session_write_close(),但如果你的PHP环境开启了session.auto_start,脚本启动时会自动获取会话锁,不过只要session_write_close()在sleep(10)之前执行,锁就会被释放,服务器端不会阻塞第二个请求。可以通过在脚本开头加var_dump(session_status());确认会话状态,确保session_write_close()确实生效。
解决方案
方法1:给URL添加唯一标识
给两个请求的URL加上不同的查询参数,让浏览器认为是不同的请求,从而并发发送:
async function test() { fetch('api/v1/test?t=' + Date.now()) fetch('api/v1/test?t=' + Date.now()) } test();
方法2:改用POST请求
浏览器不会对POST请求做这种排队优化,直接修改请求方法即可:
async function test() { fetch('api/v1/test', { method: 'POST' }) fetch('api/v1/test', { method: 'POST' }) } test();
方法3:确认PHP会话操作无遗漏
确保PHP脚本中session_write_close()之后没有再调用任何会话相关函数(比如session_start()、$_SESSION赋值等),避免重新获取会话锁。
内容的提问来源于stack exchange,提问作者KHansen
相关产品推荐
相关产品推荐

