jimmywarting / FormData

HTML5 `FormData` polyfill for Browsers and nodejs
MIT License
360 stars 102 forks source link

Suggest adding boundary setter and getter #117

Closed Chinlinlee closed 3 years ago

Chinlinlee commented 3 years ago

https://github.com/jimmywarting/FormData/blob/e6d62cb38a2d8676182bce8a0d26d2c9c4c19f0d/FormData.js#L343-L367

In my use case, I want to post the data that use "multipart/related" in content-type header.

The code shows keeping header and blob data with same boundary.

let FD = new FormData();
let xhr = new XMLHttpRequest();
FD.setBoundary('----formdata-polyfill-' + Math.random());
let boundary = FD.getBoundary();
xhr.open('POST', uploadApiUrl , true);
xhr.setRequestHeader("Accept" , "*/*");
xhr.setRequestHeader("Content-Type", `multipart/related; boundary=${boundary}`);

My FormData.js change:

constructor (form) {
        this._data = []
        this._boundary = "";
        const self = this
       /*... */
        getBoundary () {
            return this._boundary;
        }

        setBoundary (boundary) {
            this._boundary = boundary;
        }
     /**
       * [_blob description]
       *
       * @return {Blob} [description]
       */
      ['_blob'] () {
        if (!this._boundary) {
          this._boundary = '----formdata-polyfill-' + Math.random();
        }
        const chunks = []
        const boundary = this._boundary;
        for (const [name, value] of this) {
          chunks.push(`--${boundary}\r\n`)

          if (value instanceof Blob) {
            chunks.push(
              `Content-Disposition: form-data; name="${name}"; filename="${value.name}"\r\n` +
              `Content-Type: ${value.type || 'application/octet-stream'}\r\n\r\n`,
              value,
              '\r\n'
            )
          } else {
            chunks.push(
              `Content-Disposition: form-data; name="${name}"\r\n\r\n${value}\r\n`
            )
          }
        }

        chunks.push(`--${boundary}--`)

        return new Blob(chunks, {
          type: 'multipart/form-data; boundary=' + boundary
        })
      }
     /* ... */
}
jimmywarting commented 3 years ago

Never heard about multipart/related before. what benefits dose it have compared to multipart/form-data?

I'm a bit agains get/set boundary as i want this to follow the spec more closely and being isomorphic towards other formdata instances So if you have native FormData in the browser and a other package in the server then it should work the same way

I think the best way would be to utilize the https://github.com/jimmywarting/FormData/blob/master/formdata-to-blob.js You can do whatever you like with that instead of polluting the FormData instance with none spec methods

Currently i think you can work around this quite easily as it already is if you just did

blob = formData._toBlob()
blob = new Blob([blob], { type: blob.type.replace('form-data', 'related') })

xhr.open('POST', uploadApiUrl , true);
xhr.send(blob)
Chinlinlee commented 3 years ago

Thanks for your reply. Sorry that I don't know the benefits of multipart/related either. I just follow the standard call DICOMweb STOW-RS and it need to implement the POST with multipart/related header.

I will close this issue and try to use the formdata-to-blob.js instead of polluting the FormData instance. Thank you.