Nodejs express.json middleware 截断 bignum

Nodejs express.json middleware 截断 bignum

使用 express.json middleware 解析 HTTP POST data,如果 POST 是一个 JSON,里面的 value 大于 2^53 解析之后,JSON 的值就被截断了。 有人碰到过这种问题吗? 大家是怎么解决的

5 回复

标题:Node.js Express.json Middleware 截断大数字(bignum)

内容:

大家好,我最近在使用 Node.js 和 Express 框架处理 HTTP POST 请求时遇到了一个问题。当我在请求体中传递一个 JSON 数据,并且其中的数值超过了 JavaScript 中的 Number.MAX_SAFE_INTEGER(即 2^53 - 1),我发现这些数值在经过 express.json() 中间件解析后被截断了。

具体来说,如果我发送以下 JSON 数据:

{
  "bigNumber": 9007199254740992
}

在服务器端接收的数据变成了:

{
  "bigNumber": 9007199254740990
}

可以看到,数值 9007199254740992 被截断成了 9007199254740990

这个问题有人遇到过吗?大家是如何解决的?


解决方案

要解决这个问题,你可以使用 body-parser 库的一个替代版本 body-parser-bignum,它支持解析更大的数字。以下是具体步骤:

  1. 安装 body-parser-bignum
npm install body-parser-bignum
  1. 使用 body-parser-bignum 替换 express.json()
const express = require('express');
const bodyParserBignum = require('body-parser-bignum');

const app = express();

app.use(bodyParserBignum({ limit: '10mb' }));

app.post('/data', (req, res) => {
  console.log(req.body); // 现在可以正确处理大数字
  res.send('Data received');
});

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

通过这种方式,你可以确保在处理包含大数字的 JSON 数据时不会出现截断问题。希望这能帮到你!


大数字…统一字符串…

遗留系统,用node重写了,原来接口都定义好了 看来只能这样了,新开一个接口,用字符串来表示

在 Node.js 中,express.json() middleware 默认情况下会将所有数字解析为 JavaScript 数字类型,而 JavaScript 数字的最大安全整数是 (2^{53} - 1)。如果你需要处理更大的整数(如大于 (2^{53}) 的整数),你可以使用第三方库来解析这些大整数。

解决方案

一种常见的解决方案是使用 bignumbignumber.js 库来处理大整数。

使用 bignum

  1. 安装 bignum 库:

    npm install bignum
    
  2. 创建自定义的中间件来解析大整数:

    const express = require('express');
    const bignum = require('bignum');
    
    const app = express();
    
    app.use((req, res, next) => {
        if (req.headers['content-type'] === 'application/json') {
            let body = '';
            req.on('data', chunk => {
                body += chunk.toString();
            });
            req.on('end', () => {
                try {
                    const parsedBody = JSON.parse(body);
                    const bigNumObject = {};
                    for (let key in parsedBody) {
                        if (!isNaN(parsedBody[key])) {
                            bigNumObject[key] = bignum(parsedBody[key]);
                        } else {
                            bigNumObject[key] = parsedBody[key];
                        }
                    }
                    req.body = bigNumObject;
                    next();
                } catch (err) {
                    next(err);
                }
            });
        } else {
            next();
        }
    });
    
    app.post('/', (req, res) => {
        console.log(req.body); // 输出 bignum 对象
        res.send('Received');
    });
    
    app.listen(3000, () => {
        console.log('Server is running on port 3000');
    });
    

使用 bignumber.js

  1. 安装 bignumber.js 库:

    npm install bignumber.js
    
  2. 创建自定义的中间件来解析大整数:

    const express = require('express');
    const BigNumber = require('bignumber.js');
    
    const app = express();
    
    app.use((req, res, next) => {
        if (req.headers['content-type'] === 'application/json') {
            let body = '';
            req.on('data', chunk => {
                body += chunk.toString();
            });
            req.on('end', () => {
                try {
                    const parsedBody = JSON.parse(body);
                    const bigNumObject = {};
                    for (let key in parsedBody) {
                        if (!isNaN(parsedBody[key])) {
                            bigNumObject[key] = new BigNumber(parsedBody[key]);
                        } else {
                            bigNumObject[key] = parsedBody[key];
                        }
                    }
                    req.body = bigNumObject;
                    next();
                } catch (err) {
                    next(err);
                }
            });
        } else {
            next();
        }
    });
    
    app.post('/', (req, res) => {
        console.log(req.body); // 输出 BigNumber 对象
        res.send('Received');
    });
    
    app.listen(3000, () => {
        console.log('Server is running on port 3000');
    });
    

通过以上两种方法,你可以确保处理大于 (2^{53}) 的整数时不会被截断。选择适合你的需求的库即可。

回到顶部