Pino(pinojs)仅记录部分HTTP请求:Safari下POST重定向无日志
Pino HTTP日志在Safari下不记录返回重定向的POST请求(关联connect-pg-simple)
问题现象
基于Node.js + Express + PostgreSQL的Web应用中,添加pino-http日志后出现以下异常:
- 仅Safari浏览器中,返回重定向的HTTP POST请求不会被pino记录;
- 使用Chrome或curl发起相同请求时,日志正常生成;
- 移除
connect-pg-simple作为express-session的存储后端后,问题完全消失; - 全程无任何报错信息,仅表现为日志缺失。
复现代码如下:
import { default as express } from 'express' import { default as pinoHttp } from 'pino-http' import { default as session } from 'express-session'; import { default as sessionStore } from 'connect-pg-simple'; import { default as pg } from 'pg'; const Pool = pg.Pool const pool = new Pool() const reqLogger = pinoHttp({ level: 'info', enabled: true }) const app = express() app.use(session({ secret: 'secret', name: 'sessionId', resave: false, rolling: true, saveUninitialized: true, store: new (sessionStore(session))({ pool: pool }), cookie: { secure: 'auto', maxAge: 30 * 24 * 60 * 60 * 1000 } })) app.use(reqLogger) app.get('/', (req, res, next) => { const html = ` <form method="POST" action="/"> <div> <label for="floatingInput">Username</label> <input name="username" type="text" id="floatingInput"> </div> <div> <label for="floatingPassword">Password</label> <input name="password" type="password" id="floatingPassword"> </div> <button type="submit">Log in</button> </form>` res.send(html) }) app.post('/', (req, res, next) => { res.redirect('/') }) app.listen(8081, () => { console.log('Server running') })
原因分析
核心冲突来自组件异步时机与Safari的重定向处理逻辑:
- pino-http默认依赖响应的
finish事件生成日志,该事件需等待响应完全发送到客户端后触发; - 开启
rolling: true时,express-session会通过connect-pg-simple异步更新session的过期时间(写入PostgreSQL); - Safari收到重定向响应后会立即断开连接,导致Node.js端的
finish事件未触发,pino因此无法生成日志; - Chrome/curl的重定向处理会等待响应完全结束,所以
finish事件能正常触发。
解决方案
方案1:手动等待Session保存完成后再重定向
在POST路由中,先等待session的异步保存操作完成,再发送重定向响应,确保finish事件能被pino捕获:
app.post('/', async (req, res, next) => { // 等待session保存到PostgreSQL完成 await new Promise(resolve => req.session.save(resolve)); res.redirect('/'); })
方案2:调整Pino的日志触发时机
修改pino-http配置,强制在响应发送时记录日志,不依赖finish事件:
const reqLogger = pinoHttp({ level: 'info', enabled: true, onResponse: (req, res) => { req.log.info({ method: req.method, url: req.url, statusCode: res.statusCode }, 'Request handled'); } })
方案3:临时调整Express-Session配置(验证用)
如果业务允许,可临时关闭rolling配置,避免每次请求触发session异步更新,验证问题是否消失:
app.use(session({ // ...其他配置 rolling: false, // 关闭每次请求更新session过期时间 // ...其他配置 }))
验证步骤
- 应用上述任一方案后重启服务;
- 使用Safari访问页面并提交POST表单;
- 查看pino日志,确认POST请求已被正常记录。
内容的提问来源于stack exchange,提问作者rlp
相关产品推荐
相关产品推荐

