Nodejs中http协议content-type解析问题

Nodejs中http协议content-type解析问题

今天iOS同事说上传文件的接口不能用了…VC上没看到代码改动…然后查,发现APP运行在32位iOS系统OK,64位就悲剧了…原因呢?… 上传文档的Content-Type在64位系统上被偷偷加了一个charset属性,如下:

multipart/form-data; charset=utf-8; boundary=0xKhTmLbOuNdArY

然后看了下multiparty的源码,它匹配Content-Type的正则如下:

/^multipart\/(form-data|related);\s*boundary=(?:"([^"]+)"|([^;]+))$/i;

果然,根本就匹配不上,所以解析自然出错(Express@3.4.2)。

我对http协议syntax了解不多,还望论坛的大大们看看,这个是什么个情况?@MiguelValentine 大神

参考?

As with all multipart MIME types, each part has an optional “Content-Type” header that defaults to “text/plain”. User agents should supply the “Content-Type” header, accompanied by a “charset” parameter.


7 回复

(:з」∠) 兄弟你艾特错人了。向我这种不写正则的懒人,都是用的数组解的。


Node.js 中 HTTP 协议 Content-Type 解析问题

今天iOS同事反映上传文件的接口无法正常工作。检查后发现,在32位iOS系统上一切正常,但在64位iOS系统上出现问题。原因是上传文档的 Content-Type 在64位系统上被添加了一个 charset 属性,具体如下:

multipart/form-data; charset=utf-8; boundary=0xKhTmLbOuNdArY

接下来,我查看了 multiparty 库的源码,发现它用来匹配 Content-Type 的正则表达式如下:

/^multipart\/(form-data|related);\s*boundary=(?:"([^"]+)"|([^;]+))$/i;

这个正则表达式并没有考虑到 charset 参数的存在,因此在新的 Content-Type 字符串中无法正确匹配,导致解析失败。

如何解决?

为了解决这个问题,我们需要更新 multiparty 的正则表达式,使其能够处理包含 charset 参数的情况。可以修改正则表达式如下:

/^multipart\/(form-data|related);\s*(charset=[^;]+;\s*)?boundary=(?:"([^"]+)"|([^;]+))$/i;

这里的关键在于:

  1. 增加了一个可选的 charset 参数匹配部分 charset=[^;]+;,这样可以匹配 charset=utf-8; 这样的字符串。
  2. charset 参数部分是可选的,通过 ? 表示非必需。
  3. 其余部分保持不变,确保 boundary 参数仍然能够正确匹配。

示例代码

假设我们有一个简单的 Express 路由处理文件上传:

const express = require('express');
const multiparty = require('multiparty');

const app = express();

app.post('/upload', (req, res) => {
    const form = new multiparty.Form();
    
    form.parse(req, (err, fields, files) => {
        if (err) {
            console.error(err);
            return res.status(500).send('Error parsing form data');
        }
        
        console.log('Fields:', fields);
        console.log('Files:', files);
        res.send('File uploaded successfully!');
    });
});

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

如果需要自定义 multiparty 的正则表达式,可以通过继承 multiparty.Parser 类来自定义解析逻辑。

总结

通过修改 multiparty 的正则表达式,我们可以使它能够正确处理包含 charset 参数的 Content-Type 字符串。这将有助于避免在不同系统环境下出现解析错误的问题。

希望这些信息对你有所帮助!

[@MiguelValentine](/user/MiguelValentine) 那这个charset是应该要还是不要呀~

[@DevinXian](/user/DevinXian) 你能写这个正则,难道还不能再加个charset了?

在中间加一段charset不就行了吗?

/^multipart\/(form-data|related);\s*(charset=[\S]*)?\s*boundary=(?:"([^"]+)"|([^;]+))$/i

从你提供的信息来看,问题在于Content-Type头部字段中包含了额外的参数charset=utf-8,而现有的正则表达式没有考虑到这一点。在HTTP规范中,Content-Type可以包含多个参数,因此我们需要更新正则表达式以匹配这些参数。

示例代码

你可以使用以下更新后的正则表达式来匹配Content-Type头部字段:

const contentTypeRegex = /^multipart\/(form-data|related);.*boundary=(?:"([^"]+)"|([^;]+));?.*$/i;

function parseContentTypeHeader(contentType) {
    const match = contentType.match(contentTypeRegex);
    if (!match) {
        throw new Error('Invalid Content-Type format');
    }

    // 去掉引号并返回边界字符串
    return (match[2] || match[3]).replace(/"/g, '');
}

// 示例用法
const contentType = 'multipart/form-data; charset=utf-8; boundary=0xKhTmLbOuNdArY';
const boundary = parseContentTypeHeader(contentType);
console.log(boundary); // 输出: 0xKhTmLbOuNdArY

解释

  • 正则表达式:更新后的正则表达式/^multipart\/(form-data|related);.*boundary=(?:"([^"]+)"|([^;]+));?.*$/i能够匹配带有任意参数的Content-Type头部字段。
    • .*允许中间部分包含任意字符。
    • (?"([^"]+)"|([^;]+))允许边界字符串既可以是不带引号的字符串,也可以是带引号的字符串。
  • parseContentTypeHeader函数:该函数接受一个Content-Type字符串,并使用正则表达式进行匹配。如果匹配成功,则提取并返回边界字符串。

通过这种方式,你可以正确地解析包含额外参数的Content-Type头部字段。希望这能解决你的问题!

回到顶部