Node.js上传解析XML Express中间件处理XML文件流

9次阅读

express需用express.raw({type:[‘application/xml’,’text/xml’]})捕获xml原始流,req.body为buffer,须tostring()后交xml2js.parsestring()解析,注意编码、命名空间及大文件流式处理。

Node.js上传解析XML Express中间件处理XML文件流

Express里怎么接收到XML文件流

Express默认不解析XML,req.body 对XML请求是空的,除非你手动挂载解析中间件。别指望express.json()express.urlencoded()能处理它——它们只认application/jsonapplication/x-www-form-urlencoded

真实场景中,客户端常以application/xmltext/xml发POST请求(比如SOAP调用、第三方系统回调),这时必须靠raw中间件捕获原始字节流:

  • express.raw({ type: ['application/xml', 'text/xml'] }),确保req.bodyBuffer
  • 顺序很重要:必须放在路由前、其他body解析中间件之后(避免被提前消费)
  • 如果同时支持JSON和XML,得分开写两套raw,不能合并type通配——express.json()会吃掉所有req.body,导致后续raw拿不到数据

用xml2js解析Buffer时为什么报“Cannot read PropertyLength’ of undefined

这是最常见报错,根本原因是没等req.body完整就传给了xml2js.parseString()。Express的raw中间件确实把整个请求体转成Buffer了,但如果你在req.on('data')里手动拼接、又没处理req.on('end'),或者误用了req.pipe()req.body就会是undefined

正确做法只有一条:信任express.raw,直接用req.body

app.post('/api/data', express.raw({ type: 'application/xml' }), (req, res) => {   if (!req.body || req.body.length === 0) {     return res.status(400).send('Empty XML');   }   xml2js.parseString(req.body.toString(), (err, result) => {     if (err) return res.status(400).send('Invalid XML');     console.log(result);   }); });
  • req.bodyBuffer,必须先.toString()再喂给xml2js.parseString()
  • 别用xml2js.parseStringPromise()直接传Buffer——它不接受二进制,会静默失败
  • 大文件(>1MB)慎用toString(),可能触发内存告警;此时该用xml2js.Parser({ async: true })配合流式解析

为什么XML里中文变成乱码或解析出空对象

XML声明里的编码(如<?xml version="1.0" encoding="GBK"?>)和实际传输编码不一致,是乱码主因。node.js http模块默认按UTF-8解码,遇到GBK/GB2312就崩。

  • 强制统一用UTF-8:让客户端发XML时声明encoding="UTF-8",且HTTP头Content-Type也带; charset=utf-8
  • 实在没法改客户端?用iconv-lite转码:iconv.decode(req.body, 'gbk')再传给xml2js
  • 解析后取值为空?检查XML是否含命名空间(xmlns)。xml2js默认把命名空间当普通属性,需加选项{ mergeAttrs: true, explicitRoot: false }才容易取到result.root.item这类结构

大XML文件上传时内存爆满或超时

Express默认限制req.body最大100KB,express.raw()默认不限但node.js HTTP服务器有limits,上传几MB的XML很容易卡死或OOM。

  • 调大限制:express.raw({ type: 'application/xml', limit: '5mb' })
  • 超时控制:在app.use()前加app.use((req, res, next) => { req.setTimeout(30000); next(); })
  • 真正要处理GB级XML?放弃req.body,改用req.pipe()直连xml2js.Parser流式解析,避免全量加载到内存

流式解析不是银弹——你要自己处理XML事件on('opentag')on('text')),没法一键得JSON。但对日志归档、etl这类场景,省下的内存和稳定性远比开发多花半小时值。

text=ZqhQzanResources