【问题标题】:MongoDB GridFS "illegal chunk format' exceptionMongoDB GridFS“非法块格式”异常
【发布时间】:2025-12-13 00:50:02
【问题描述】:

我一直在用 Node.js 编写一个将图像存储在 MongoDB 的 GridFS 文件系统中的应用程序。

我已通过该应用上传图片,并且图片似乎已正确存储:

$ mongofiles -v -d speaker-karaoke get howard-basement-100x115.jpg
Tue Jul 17 12:14:16 creating new connection to:127.0.0.1
Tue Jul 17 12:14:16 BackgroundJob starting: ConnectBG
Tue Jul 17 12:14:16 connected connection!
connected to: 127.0.0.1
done write to: howard-basement-100x115.jpg

这从 MongoDB 中抓取了 .jpg,我可以毫无问题地打开它,所以看起来我上传的内容已正确存储。

但是,在我正在运行的应用程序中,当我尝试读取同一个文件时,我得到:

12:15:44 web.1     | started with pid 89621
12:15:45 web.1     | Connecting to mongodb://localhost/speaker-karaoke
12:15:45 web.1     | Speaker Karaoke express app started on 5000
12:15:48 web.1     | DEBUG: Get review thumbnail for 5005b7550333650000000001
12:15:48 web.1     | 
12:15:48 web.1     | node.js:201
12:15:48 web.1     |         throw e; // process.nextTick error, or 'error' event on first tick
12:15:48 web.1     |               ^
12:15:48 web.1     | Error: Illegal chunk format
12:15:48 web.1     |     at Error (unknown source)
12:15:48 web.1     |     at new <anonymous> (/Users/hlship/workspaces/github/speaker-karaoke/node_modules/mongodb/lib/mongodb/gridfs/chunk.js:43:11)
12:15:48 web.1     |     at /Users/hlship/workspaces/github/speaker-karaoke/node_modules/mongodb/lib/mongodb/gridfs/gridstore.js:488:24
12:15:48 web.1     |     at Cursor.nextObject (/Users/hlship/workspaces/github/speaker-karaoke/node_modules/mongoose/node_modules/mongodb/lib/mongodb/cursor.js:462:5)
12:15:48 web.1     |     at [object Object].<anonymous> (/Users/hlship/workspaces/github/speaker-karaoke/node_modules/mongoose/node_modules/mongodb/lib/mongodb/cursor.js:456:12)
12:15:48 web.1     |     at [object Object].g (events.js:156:14)
12:15:48 web.1     |     at [object Object].emit (events.js:88:20)
12:15:48 web.1     |     at Db._callHandler (/Users/hlship/workspaces/github/speaker-karaoke/node_modules/mongoose/node_modules/mongodb/lib/mongodb/db.js:1290:25)
12:15:48 web.1     |     at /Users/hlship/workspaces/github/speaker-karaoke/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/server.js:329:30
12:15:48 web.1     |     at [object Object].parseBody (/Users/hlship/workspaces/github/speaker-karaoke/node_modules/mongoose/node_modules/mongodb/lib/mongodb/responses/mongo_reply.js:118:5)
12:15:48 web.1     | process terminated
12:15:48 system    | sending SIGTERM to all processes

使用此代码(CoffeeScript,用于 Express):

  app.get "/images/review-thumbnail/:id", (req, res) ->

    id = req.params.id

    util.debug "Get review thumbnail for #{id}"

    store = new GridStore mongoose.connection.db, new ObjectID(id), null, "r"

    store.open (err, file) ->

      throw err if err

      util.debug "Store open for #{id}, type = #{file.contentType}"

      # TODO: Scale the image before sending it!

      res.header "Content-Type", file.contentType

      store.stream(true).pipe res

所以它似乎甚至没有进入传递给 store.open() 的回调。

当您知道 id 而不是文件名时,打开 GridFS 文件是否有问题?

顺便说一句:

$ npm ls
speaker-karaoki@0.0.1 /Users/hlship/workspaces/github/speaker-karaoke
├─┬ blueimp-file-upload-node@1.0.2  extraneous
│ ├── formidable@1.0.11 
│ ├── imagemagick@0.1.2 
│ └── node-static@0.6.0 
├── coffee-script@1.3.3 
├─┬ connect-assets@2.1.9 
│ ├── connect-file-cache@0.2.4 
│ ├── mime@1.2.2 
│ ├─┬ snockets@1.3.4 
│ │ ├── coffee-script@1.3.3 
│ │ ├── dep-graph@1.0.1 
│ │ └── uglify-js@1.0.7 
│ └── underscore@1.1.7 
├─┬ express@2.5.9 
│ ├─┬ connect@1.9.1 
│ │ └── formidable@1.0.11 
│ ├── mime@1.2.4 
│ ├── mkdirp@0.3.0 
│ └── qs@0.4.2 
├─┬ jade@0.26.0 
│ ├── commander@0.5.2 
│ └── mkdirp@0.3.0 
├─┬ mongodb@1.0.2 
│ └── bson@0.0.6 
├─┬ mongoose@2.7.0 
│ ├── hooks@0.2.1 
│ └─┬ mongodb@1.0.2 
│   └── bson@0.0.6 
├─┬ passport@0.1.10 
│ └── pkginfo@0.2.3 
├─┬ passport-twitter@0.1.3 
│ ├─┬ passport-oauth@0.1.9 
│ │ ├── oauth@0.9.7 
│ │ └── passport@0.1.11 
│ └── pkginfo@0.2.3 
├── sass@0.5.0 
└── underscore@1.3.3 

这是失败的功能:

var Chunk = exports.Chunk = function(file, mongoObject) {
  if(!(this instanceof Chunk)) return new Chunk(file, mongoObject);

  this.file = file;
  var self = this;
  var mongoObjectFinal = mongoObject == null ? {} : mongoObject;

  this.objectId = mongoObjectFinal._id == null ? new ObjectID() : mongoObjectFinal._id;
  this.chunkNumber = mongoObjectFinal.n == null ? 0 : mongoObjectFinal.n;
  this.data = new Binary();

  if(mongoObjectFinal.data == null) {
  } else if(typeof mongoObjectFinal.data == "string") {
    var buffer = new Buffer(mongoObjectFinal.data.length);
    buffer.write(mongoObjectFinal.data, 'binary', 0);
    this.data = new Binary(buffer);
  } else if(Array.isArray(mongoObjectFinal.data)) {
    var buffer = new Buffer(mongoObjectFinal.data.length);
    buffer.write(mongoObjectFinal.data.join(''), 'binary', 0);
    this.data = new Binary(buffer);
  } else if(mongoObjectFinal.data instanceof Binary || Object.prototype.toString.call(mongoObjectFinal.data) == "[object Binary]") {    
    this.data = mongoObjectFinal.data;
  } else if(Buffer.isBuffer(mongoObjectFinal.data)) {
  } else {
    throw Error("Illegal chunk format");
  }
  // Update position
  this.internalPosition = 0;
};

解决方案

在此处更新解决方案,因为它在下面的 cmets 中无法正确呈现。

问题是重复;有两个副本,即使版本相同,mongodb 和 bson。

幸运的是,mongoose 将它所需的 mongodb 导出为属性 mongo,因此我能够从我的 package.json 中删除显式 mongodb 并进行了更改:

mongo = require "mongodb"
mongoose = require "mongoose"

到:

mongoose = require "mongoose"
mongo = mongoose.mongo

现在看起来不错;我仍然认为模块系统需要一种认可的方式来访问依赖项依赖项(对于一个 dep 不够周到暴露其 deps 的情况)。

【问题讨论】:

  • 你是用node/mongo写GridFS文件,还是其他方式?
  • 我正在使用 node/mongo 写入 GridFS;如果有帮助,我可以显示该代码,但是 mongofiles 命令行工具可以正确读取文件内容的事实让我觉得我做得很好。
  • 是的,只是仔细检查。 GridFS 没有真正的标准,所以我想知道这是否是驱动程序不一致。不过,由于您是使用 Node 驱动程序编写的,所以我不认为就是这样。
  • 更改了我的代码以根据 ObjectID 生成文件名。在为写入和读取创建 GridStore 时使用文件名。但是,这并没有改变行为,因此文件名(或缺少)并不是真正的问题。
  • 嗯。似乎现在正在工作。我刚刚经历了一些激进的 npm 工作;删除 node_modules 并重新运行 npm install。我知道我有两个相互竞争的 mongodb 模块副本,这可能会导致问题。我想进一步研究。

标签: node.js mongodb gridfs


【解决方案1】:

很确定它是 mongodb 模块的重复副本(相同版本);删除 node_modules 和 nmp install 似乎已经修复它。

【讨论】:

  • 该死,它的背面。刚刚更新到 mongoose@3.1.2 和 mongodb@1.1.7。 mongodb有两个副本,但是都是同一个版本。
  • 而且我可以验证 mongofiles 命令可以正确读取内容。
  • 好吧,我想我这次真的解决了。我现在很确定这是 mongodb 和 bson 模块的两个版本之间的冲突。
  • 参见上面的 solution 注释(我不得不将它移到那里,因为 cmets 内部的格式太有限了)。