首页
/ Electron 中 UploadData 对象详解:请求上传体的结构定义、API 使用与源码实现

Electron 中 UploadData 对象详解:请求上传体的结构定义、API 使用与源码实现

2026-09-06 17:12:25作者:贡沫苏Truman

Electron 的 UploadData 对象是网络栈向 JS 层暴露"正在上传的请求体"的标准数据结构,主要出现在 webRequest 事件细节与协议处理相关的结构中。读懂它的三个字段、弄清楚它在 session.webRequest 监听器中的出现位置,并对照 源码转换器 了解 Chromium 底层四种上传元素是如何映射成 JS 对象的,你就能在拦截请求时准确识别普通字节、磁盘文件、Blob 和流式上传这四类载荷。

UploadData 对象:官方定义与字段语义

UploadData 官方结构定义 非常紧凑,全文只有三个字段,这里完整继承并展开说明:

字段 类型 是否可选 说明
bytes Buffer 必填 正在发送的内容(Content being sent)
file string 可选 正在上传的文件路径(Path of file being uploaded)
blobUUID string 可选 Blob 数据的 UUID,配合 ses.getBlobData 方法取回实际数据

三个字段分别对应三种典型的上传场景:

  • bytes:请求体在内存中、可以直接以 Buffer 形式读取时(例如 fetch 上传字符串/ArrayBuffer),转换器会把底层字节复制成 JS Buffer 挂到该字段上;
  • file:上传的是一段磁盘文件(例如 multipart/form-data 中通过 Filefs 路径构造的部分)时,JS 层拿到的只是文件路径字符串,文件内容并不会被整体拷贝进内存;
  • blobUUID:上传数据来自 Blob(DataPipe 形式)时,对象上只携带一个 UUID 标识符,需要通过 session 实例的 ses.getBlobData(identifier) 方法按标识取回数据——这一点在官方文档中作为 blobUUID 字段的说明被明确写出。

UploadData 出现的位置

webRequest 事件中的 details.uploadData

WebRequest 模块文档 中,uploadDataUploadData[] 数组形式出现在两个监听器的 details 对象里:

  1. webRequest.onBeforeRequest([filter, ]listener)details.uploadData[UploadData[]](docs/api/structures/upload-data.md)(非可选),文档原文明确写道 "The uploadData is an array of UploadData objects"。该事件在请求即将发出时触发,监听器必须通过 callback 返回一个含 cancelredirectURL 等可选字段的 response 对象。
  2. webRequest.onBeforeSendHeaders([filter, ]listener)details.uploadData[UploadData[]](docs/api/structures/upload-data.md)(可选,因为并非所有请求都带上传体),此时 details 中还会附带 requestHeaders,适合在发头阶段检查上传内容并改写请求头。

两个监听器都支持通过 WebRequestFilter 按 URL 过滤,文档给出的合法 URL 模式 包括:

'<all_urls>'
'http://foo:1234/'
'http://foo.com/'
'*://*/*'
'*://example.com/*'
'http://*.foo:1234/'
'file://foo:1234/bar'

ProtocolRequest 结构中的可选 uploadData

ProtocolRequest 结构 定义了描述一次请求的对象:urlreferrermethodheaders,以及可选的 uploadData 字段,其类型同样是 UploadData[]。也就是说,在协议处理的请求描述中,上传体同样以 UploadData 数组的形式暴露给嵌入方。

源码实现:Chromium 上传数据如何变成 UploadData

从源码结构看,UploadData 并不是 Electron 自己构造的数据,而是 Chromium 网络栈请求体对象的 JS 投影。关键转换逻辑位于 Converternetwork::ResourceRequestBody::ToV8:它遍历底层 network::ResourceRequestBodyelements(),按 DataElement::Tag 枚举逐一分发,构造出 JS 对象数组。四种底层元素到 JS 字段的映射关系如下(见 net_converter.cc):

底层 mojom 元素 type 字段 写入的 JS 属性
kFileDataElementFile file filefilePathoffsetlengthmodificationTime
kBytesDataElementBytes rawData bytes(通过 electron::Buffer::Copy 拷贝字节)
kDataPipe(Blob) blob blobUUIDdataPipe
kChunkedDataPipe(流) stream bodyReadableStream 包装)

可以推断出几个文档未展开、但源码中明确存在的事实:

  1. 文档字段是"简化视图"。官方结构文档只列了 bytes/file/blobUUID 三个字段,而转换器实际还会写入 type 以及文件元素的 filePathoffsetlengthmodificationTimetype 字段(取值 file/rawData/blob/stream)可以看作区分四种载荷的判断依据。
  2. 字节拷贝发生在转换时kBytes 分支调用 electron::Buffer::Copy,意味着 bytes Buffer 是底层数据的一份副本;而 kFile 分支只传递路径,不触发内容读取,对大文件上传的拦截检查(只读路径、校验文件名等)是零拷贝的。
  3. Blob 的数据管道生命周期绑定在 UploadData 对象上。源码注释写道 "The lifetime of data pipe is bound to the uploadData object",即 dataPipe 属性(DataPipeHolder)与 uploadData 对象同生命周期——如果你要异步处理 Blob 数据,需要保证持有该 uploadData 对象或及时用 getBlobData 取回内容。
  4. getBlobData 有被重构的意图源码中的 TODO 注释 表明:在 NetworkService 重构之后,旧的 blobUUID API 变得"不必要地复杂",未来计划弃用 getBlobData 并直接返回 DataPipeHolder 包装器。因此在使用 blobUUID 时宜将其视为稳定的当前 API,但不必为它设计过度复杂的持久化方案。

通过 getBlobData 取回 Blob 内容

对携带 blobUUID 的 UploadData,官方文档给出的取数方式是 ses.getBlobData(identifier),其定义位于 Session API 文档。典型的使用链路是:webRequest 监听器拿到 details.uploadData 中某个元素的 blobUUID → 调用对应 sessiongetBlobData → 按 UUID 换回 Blob 数据。对于 file 元素,则直接根据 file 路径用 fs API 处理即可。

与相近结构的区分

仓库中还有几个容易与 UploadData 混淆的结构,注意它们的适用场景不同:

  • UploadRawData / UploadFile{type: 'rawData', bytes}{type: 'file', filePath, offset, length, modificationTime} 两种结构,是 PostBody 对象data 数组的元素类型。PostBody(含 contentTypeboundarycontentType 只允许 application/x-www-form-urlencodedmultipart/form-data,对应 HTML 表单的 enctype)用于表单提交场景,与 UploadData 的网络栈来源是两条不同的暴露路径;
  • ProtocolResponseUploadData:只有 contentType(MIME 类型)与 data(string | Buffer)两个字段,出现在 ProtocolResponse 中,属于协议处理器侧的上传响应数据,与请求拦截侧的 UploadData 不是一回事。

实战示例:在 webRequest 中检查上传内容

结合上述结构定义,一个合法的拦截检查逻辑如下(字段取值与 UploadData 定义webRequest 事件细节 完全对应):

const { session } = require('electron')

const ses = session.defaultSession

ses.webRequest.onBeforeRequest(
  { urls: ['*://*/*'] },
  (details, callback) => {
    for (const chunk of details.uploadData) {
      if (chunk.file) {
        // 磁盘文件上传:只拿到路径,按需再读文件
        console.log('file upload:', chunk.file)
      } else if (chunk.blobUUID) {
        // Blob 上传:用 UUID 异步取回数据
        ses.getBlobData(chunk.blobUUID).then(data => {
          console.log('blob data size:', data.length)
        })
      } else if (chunk.bytes) {
        // 内存中的原始字节
        console.log('raw bytes:', chunk.bytes.length)
      }
    }
    callback({})
  }
)

注意:onBeforeRequestuploadData 是必填字段,而 onBeforeSendHeaders 中它是可选的,后者使用时应先做空值判断。

小结

  • UploadDatabytes(Buffer,必填)、file(string,可选)、blobUUID(string,可选)三字段组成,分别覆盖内存字节、磁盘文件、Blob 三类上传内容;
  • 它主要出现在 webRequestonBeforeRequest/onBeforeSendHeaders 细节与 ProtocolRequest 结构中,以数组形式暴露;
  • 从源码看,它由 net_converter.cc 将 Chromium 的 ResourceRequestBody 四种 DataElement(file / rawData / blob / stream)转换而来,实际对象上还带有 type 等文档未列出的字段;
  • 取回 Blob 数据使用 ses.getBlobData(identifier);与 PostBodyProtocolResponseUploadData 等相似结构应明确区分场景后再使用。
登录后查看全文
热门项目推荐
相关项目推荐