如何用TypeBox解析HTTP请求?解决循环结构JSON转换错误
TypeBox验证请求对象时的循环引用问题解决
问题场景
使用TypeBox验证整个Express Request对象时触发循环引用错误,但单独验证request.body或request.params可正常工作。
出错代码
import { Type } from '@sinclair/typebox'; import { Value } from '@sinclair/typebox/value'; const metaReqSchema = Type.Object({ name: Type.String() }); const reqSchema = Type.Object({ params: Type.Object({ idParam: Type.String() }), body: metaReqSchema }); @httpPost('/version/:idParam') public async getMeta(request: Request, response: Response, next: NextFunction) { try { const dataInputValidated = Value.Decode(reqSchema, request); console.log('验证后的输入', dataInputValidated.body); console.log('参数', dataInputValidated.params); return response.status(200).json({ data: 1 }); } catch (err) { return response.status(500).json({ data: err }); } }
错误信息
Converting circular structure to JSON --> starting at object with constructor 'Socket' | property 'parser' -> object with constructor 'HTTPParser' --- property 'socket' closes the circle
正常运行的代码片段
单独验证request.body时能正常工作:
try { const dataInputValidated = Value.Decode(metaReqSchema, request.body); console.log('验证后的输入', dataInputValidated); console.log('参数', dataInputValidated); return response.status(200).json({ data: dataInputValidated }); } catch (err) { return response.status(500).json({ error: err }); }
问题原因
Express的Request对象包含大量带循环引用的内部属性(如socket、parser等),直接将整个Request对象传入Value.Decode时,TypeBox会保留原对象的所有属性,后续尝试将该对象序列化为JSON返回时,就会触发循环引用错误。同时Value.Decode默认返回原对象的引用,而非仅包含schema定义属性的新对象。
解决方案
方法1:传入仅包含所需属性的纯对象
不要直接传入整个Request对象,构造符合reqSchema结构的纯对象,只包含params和body:
@httpPost('/version/:idParam') public async getMeta(request: Request, response: Response, next: NextFunction) { try { const requestData = { params: request.params, body: request.body }; const dataInputValidated = Value.Decode(reqSchema, requestData); console.log('验证后的输入', dataInputValidated.body); console.log('参数', dataInputValidated.params); return response.status(200).json({ data: 1 }); } catch (err) { return response.status(500).json({ error: err instanceof Error ? err.message : err }); } }
方法2:使用Value.Encode生成纯净对象
如果需要仅包含schema定义属性的全新对象(而非原对象引用),可以用Value.Encode方法,它会根据schema过滤并生成新对象,彻底避免循环引用:
const requestData = { params: request.params, body: request.body }; const dataInputValidated = Value.Encode(reqSchema, requestData);
内容的提问来源于stack exchange,提问作者Mr X
相关产品推荐
相关产品推荐

