zoukankan      html  css  js  c++  java
  • node 对于 formdata 数据解析处理

    文件上传数据格式:

    ------WebKitFormBoundaryjlaXz2OrLImcaQJb // 分界标识
    Content-Disposition: form-data; name="file"; filename="hostFile.txt" // 头字段信息
    Content-Type: text/plain // 内容类型
    
    文件内容
    ------WebKitFormBoundaryjlaXz2OrLImcaQJb
    Content-Disposition: form-data; name="fileSize"
    
    1024
    ------WebKitFormBoundaryjlaXz2OrLImcaQJb
    Content-Disposition: form-data; name="fileName"
    
    text.txt
    ------WebKitFormBoundaryjlaXz2OrLImcaQJb-- // 后面两个 ‘--’ 代表结束

    第一步:根据 request 的 data 事件监听取得请求信息及上传数据

    第二步:取得请求头的 content-type 字段中的 boundary 后面的分界标识值

    Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryjlaXz2OrLImcaQJb
    var m = this.headers['content-type'].match(/boundary=(?:"([^"]+)"|([^;]+))/i);
    // m[1] || m[2]

    第三步:在每次写入数据的时候,会根据规则获取头字段信息与文件内容或者字段值

    var self = this;
    req
      .on('error', function(err) {
        self._error(err);
      })
      .on('aborted', function() {
        self.emit('aborted');
        self._error(new Error('Request aborted'));
      })
      .on('data', function(buffer) {
        self.write(buffer); // 写入操作
      })
      .on('end', function() {
        if (self.error) {
          return;
        }
    IncomingForm.prototype.write = function(buffer) {
      if (this.error) {
        return;
      }
      if (!this._parser) {
        this._error(new Error('uninitialized parser'));
        return;
      }
    
      this.bytesReceived += buffer.length;
      this.emit('progress', this.bytesReceived, this.bytesExpected);
    
      var bytesParsed = this._parser.write(buffer); // multipart_parse
      if (bytesParsed !== buffer.length) {
        this._error(new Error('parser error, '+bytesParsed+' of '+buffer.length+' bytes parsed'));
      }
    
      return bytesParsed;
    };
    
    // multipart_parse
    MultipartParser.prototype.write = function(buffer) {
      var self = this,
          i = 0,
          len = buffer.length,
          prevIndex = this.index,
          index = this.index,
          state = this.state,
          flags = this.flags,
          lookbehind = this.lookbehind,
          boundary = this.boundary,
          boundaryChars = this.boundaryChars,
          boundaryLength = this.boundary.length,
          boundaryEnd = boundaryLength - 1,
          bufferLength = buffer.length,
          c,
          cl,
    ......
      for (i = 0; i < len; i++) {
    ......
      }
    ......
    }

    同时执行下面操作

    // Content-Disposition: form-data; name="fileName"
    
    headerField += b.toString(self.encoding, start, end);
    
    headerValue += b.toString(self.encoding, start, end);
    
    var m = headerValue.match(/name=("([^"]*)"|([^()<>@,;:\"/[]?={}s	/]+))/i);
    if (headerField == 'content-disposition') {
      if (m) {
        part.name = m[2] || m[3] || '';
      }
      // headerValue.match(/filename=("(.*?)"|([^()<>@,;:\"/[]?={}s	/]+))($|;s)/i);
      part.filename = self._fileName(headerValue);
    } else if (headerField == 'content-type') {
      part.mime = headerValue;
    } else if (headerField == 'content-transfer-encoding') {
      part.transferEncoding = headerValue.toLowerCase();
    }

    根据 filename 字段的值来判断是该分界内容是字段值还是文件内容

    if (part.filename === undefined) {
      var value = ''
        , decoder = new StringDecoder(this.encoding);
    
      part.on('data', function(buffer) {
        self._fieldsSize += buffer.length;
        if (self._fieldsSize > self.maxFieldsSize) {
          self._error(new Error('maxFieldsSize exceeded, received '+self._fieldsSize+' bytes of field data'));
          return;
        }
        value += decoder.write(buffer);
      });
    
      part.on('end', function() {
        self.emit('field', part.name, value);
      });
      return;
    }
    part.on(
    'data', function(buffer) { self._fileSize += buffer.length; if (self._fileSize > self.maxFileSize) { self._error(new Error('maxFileSize exceeded, received '+self._fileSize+' bytes of file data')); return; } if (buffer.length == 0) { return; } self.pause(); file.write(buffer, function() { self.resume(); }); }); part.on('end', function() { file.end(function() { self._flushing--; self.emit('file', part.name, file); self._maybeEnd(); }); });

    根据 buffer 数据获取头字段信息及内容的判断有点复杂,逻辑如此,具体操作还没理清,未完待续......

  • 相关阅读:
    OnboardSDK分析
    Ubuntu14.04安装pycharm用于Python开发环境部署,并且支持pycharm使用中文输入
    TCP/IP四层模型和OSI七层模型的概念
    二分查找
    Combination Sum
    全面解析回溯法:算法框架与问题求解
    Search Insert Position
    过滤器
    Java中Web页面信息获取
    jQuery和Ajax联动
  • 原文地址:https://www.cnblogs.com/kdcg/p/13536553.html
Copyright © 2011-2022 走看看