You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Express中间件报错:TypeError: Converting circular structure to JSON

问题描述

使用express-session与genius-lyrics包编写initSongArray中间件时,尝试返回简单JSON(如{ num: 20 })会触发TypeError: Converting circular structure to JSON错误,移除res.status.json语句后代码运行正常。

代码示例

async function initSongArray(req, res, next){
    const searches = await Client.songs.search(req.params.artist);
    let songNum = 0
    while((searches[songNum].artist.name.includes('&')) && req.params.and === 0){
        console.log("& detected")
        songNum++;
    }
    req.session.artist = searches[songNum].artist;
    req.session.songArray = await req.session.artist.songs({sort: 'popularity', perPage: 20, page: 1});
    req.session.currPage = 2
    console.log(req.session.songArray.length)
    res.status(200).json( { num: 20 } )
}

app.get('/artist/:artist/:and', initSongArray)

报错栈

>C:\Users\bgrie\Desktop\a\compsci.websites\typesiteNode\node_modules\express-session\index.js:598
var str = JSON.stringify(sess, function (key, val) {
^

TypeError: Converting circular structure to JSON
--> starting at object with constructor 'Client'
|     property 'songs' -> object with constructor 'SongsClient'
--- property 'client' closes the circle
at JSON.stringify ()
at hash (C:\Users\bgrie\Desktop\a\compsci.websites\typesiteNode\node_modules\express-session\index.js:598:18)
at isModified (C:\Users\bgrie\Desktop\a\compsci.websites\typesiteNode\node_modules\express-session\index.js:426:57)
at shouldSave (C:\Users\bgrie\Desktop\a\compsci.websites\typesiteNode\node_modules\express-session\index.js:448:11)
at ServerResponse.end (C:\Users\bgrie\Desktop\a\compsci.websites\typesiteNode\node_modules\express-session\index.js:334:11)
at ServerResponse.send (C:\Users\bgrie\Desktop\a\compsci.websites\typesiteNode\node_modules\express\lib\response.js:232:10)
at ServerResponse.json (C:\Users\bgrie\Desktop\a\compsci.websites\typesiteNode\node_modules\express\lib\response.js:278:15)
at initSongArray (C:\Users\bgrie\Desktop\a\compsci.websites\typesiteNode\index.js:70:21)
at processTicksAndRejections (node:internal/process/task_queues:96:5)

原因分析

报错根源不是返回的JSON数据,而是express-session序列化session对象时失败。你将genius-lyrics包的原生Artist对象直接存入req.session.artist,该对象内部存在循环引用:Client的songs属性指向SongsClient,而SongsClient的client属性又指向原Client,形成闭环。当调用res.json触发响应结束时,express-session会自动保存session到存储介质,此时需要将session对象序列化为JSON,循环引用结构无法被JSON.stringify处理,因此抛出错误。

解决方案

不要直接将genius-lyrics的原生对象存入session,仅提取可序列化的核心字段:

方案1:提取核心字段存入session

async function initSongArray(req, res, next){
    const searches = await Client.songs.search(req.params.artist);
    let songNum = 0
    while((searches[songNum].artist.name.includes('&')) && req.params.and === 0){
        console.log("& detected")
        songNum++;
    }
    // 提取可序列化的artist基础信息,而非存入整个对象
    const artistData = {
        id: searches[songNum].artist.id,
        name: searches[songNum].artist.name,
        url: searches[songNum].artist.url
        // 按需添加其他需要的字段
    };
    req.session.artist = artistData;
    // 直接通过原artist对象获取歌曲列表
    req.session.songArray = await searches[songNum].artist.songs({sort: 'popularity', perPage: 20, page: 1});
    req.session.currPage = 2
    console.log(req.session.songArray.length)
    res.status(200).json( { num: req.session.songArray.length } )
}

方案2:手动过滤循环引用字段

如果需要保留更多字段,可通过JSON序列化时的过滤函数移除循环引用部分:

async function initSongArray(req, res, next){
    const searches = await Client.songs.search(req.params.artist);
    let songNum = 0
    while((searches[songNum].artist.name.includes('&')) && req.params.and === 0){
        console.log("& detected")
        songNum++;
    }
    // 过滤掉导致循环引用的client属性,转为普通对象
    const plainArtist = JSON.parse(JSON.stringify(searches[songNum].artist, (key, val) => {
        if (key === 'client') return undefined;
        return val;
    }));
    req.session.artist = plainArtist;
    req.session.songArray = await searches[songNum].artist.songs({sort: 'popularity', perPage: 20, page: 1});
    req.session.currPage = 2
    console.log(req.session.songArray.length)
    res.status(200).json( { num: 20 } )
}

处理后session对象不再包含循环引用,express-session可正常序列化,res.json也能正常执行。

内容的提问来源于stack exchange,提问作者ben

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 06:54:25