Skip to content
This repository has been archived by the owner. It is now read-only.

Uploading results as empty file without mime type without errors #13

Open
evilandfox opened this issue Nov 7, 2018 · 34 comments
Open

Uploading results as empty file without mime type without errors #13

evilandfox opened this issue Nov 7, 2018 · 34 comments

Comments

@evilandfox
Copy link

@evilandfox evilandfox commented Nov 7, 2018

Have anyone same problem?

@devjv
Copy link

@devjv devjv commented Nov 8, 2018

Same problem here. Looking for a workaround, will update if I find something.

@evilandfox
Copy link
Author

@evilandfox evilandfox commented Nov 8, 2018

Problem is going from fetch polyfill package and there are PR that not merged yet
Thanks for that author, I made quick fix that resolves problem

;(function(self) {
    'use strict'

    function parseHeaders(rawHeaders) {
        var headers = new Headers()
        var preProcessedHeaders = rawHeaders.replace(/\r?\n[\t ]+/g, ' ')
        preProcessedHeaders.split(/\r?\n/).forEach(function(line) {
            var parts = line.split(':')
            var key = parts.shift().trim()
            if (key) {
                var value = parts.join(':').trim()
                headers.append(key, value)
            }
        })
        return headers
    }

    var supportsBlob =
        'FileReader' in self &&
        'Blob' in self &&
        (function() {
            try {
                new Blob()
                return true
            } catch (e) {
                return false
            }
        })()

    self.fetch = function(input, init) {
        return new Promise(function(resolve, reject) {
            var request = new Request(input, init)
            var xhr = new XMLHttpRequest()

            xhr.onload = function() {
                var options = {
                    status: xhr.status,
                    statusText: xhr.statusText,
                    headers: parseHeaders(xhr.getAllResponseHeaders() || '')
                }
                options.url =
                    'responseURL' in xhr ? xhr.responseURL : options.headers.get('X-Request-URL')
                var body = 'response' in xhr ? xhr.response : xhr.responseText
                resolve(new Response(body, options))
            }

            xhr.onerror = function() {
                reject(new TypeError('Network request failed'))
            }

            xhr.ontimeout = function() {
                reject(new TypeError('Network request failed'))
            }

            xhr.open(request.method, request.url, true)

            if (request.credentials === 'include') {
                xhr.withCredentials = true
            } else if (request.credentials === 'omit') {
                xhr.withCredentials = false
            }
            if ('responseType' in xhr && supportsBlob) {
                xhr.responseType = 'blob'
            }
            request.headers.forEach(function(value, name) {
                xhr.setRequestHeader(name, value)
            })

            xhr.send(typeof request._bodyInit === 'undefined' ? null : request._bodyInit)
        })
    }
    self.fetch.polyfill = true
})(typeof self !== 'undefined' ? self : this)

@evilandfox
Copy link
Author

@evilandfox evilandfox commented Nov 8, 2018

facebook/react-native#22063

@devjv
Copy link

@devjv devjv commented Nov 8, 2018

Thank you so much for that!

@yonahforst
Copy link

@yonahforst yonahforst commented Nov 10, 2018

I'm having this issue as well when using the ios simulator. I checked in node_modules/whatwg-fetch and it has that change that the PR added. Help!

@yonahforst
Copy link

@yonahforst yonahforst commented Nov 10, 2018

I think the problem is that whatwg-fetch is not setting the type when building the blob.

this worked for me.

function urlToBlob(url) {
  return new Promise((resolve, reject) => {
      var xhr = new XMLHttpRequest();
      xhr.onerror = reject;
      xhr.onreadystatechange = () => {
          if (xhr.readyState === 4) {
              resolve(xhr.response);
          }
      };
      xhr.open('GET', url);
      xhr.responseType = 'blob'; // convert type
      xhr.send();
  })
}

@farzd
Copy link

@farzd farzd commented Nov 12, 2018

@yonahforst thanks!!

@barrylachapelle
Copy link

@barrylachapelle barrylachapelle commented Nov 12, 2018

You the man @yonahforst

@bonham000
Copy link

@bonham000 bonham000 commented Nov 16, 2018

AWESOME @yonahforst !!!!!! Just completely saved me, thank you! 🎖

@barrylachapelle
Copy link

@barrylachapelle barrylachapelle commented Nov 16, 2018

Hey guys ... this is a huge issue for me. I am now having an issue with @yonahforst 's function... for some reason the func switching views in my app after PUT. When I use the old fetch the problem doesn't happen (alas no blob either)... is anyone else getting this with the function above?

Would rolling back SDKs fix this entire issue??

@barrylachapelle
Copy link

@barrylachapelle barrylachapelle commented Nov 16, 2018

Problem is going from fetch polyfill package and there are PR that not merged yet
Thanks for that author, I made quick fix that resolves problem

;(function(self) {
    'use strict'

    function parseHeaders(rawHeaders) {
        var headers = new Headers()
        var preProcessedHeaders = rawHeaders.replace(/\r?\n[\t ]+/g, ' ')
        preProcessedHeaders.split(/\r?\n/).forEach(function(line) {
            var parts = line.split(':')
            var key = parts.shift().trim()
            if (key) {
                var value = parts.join(':').trim()
                headers.append(key, value)
            }
        })
        return headers
    }

    var supportsBlob =
        'FileReader' in self &&
        'Blob' in self &&
        (function() {
            try {
                new Blob()
                return true
            } catch (e) {
                return false
            }
        })()

    self.fetch = function(input, init) {
        return new Promise(function(resolve, reject) {
            var request = new Request(input, init)
            var xhr = new XMLHttpRequest()

            xhr.onload = function() {
                var options = {
                    status: xhr.status,
                    statusText: xhr.statusText,
                    headers: parseHeaders(xhr.getAllResponseHeaders() || '')
                }
                options.url =
                    'responseURL' in xhr ? xhr.responseURL : options.headers.get('X-Request-URL')
                var body = 'response' in xhr ? xhr.response : xhr.responseText
                resolve(new Response(body, options))
            }

            xhr.onerror = function() {
                reject(new TypeError('Network request failed'))
            }

            xhr.ontimeout = function() {
                reject(new TypeError('Network request failed'))
            }

            xhr.open(request.method, request.url, true)

            if (request.credentials === 'include') {
                xhr.withCredentials = true
            } else if (request.credentials === 'omit') {
                xhr.withCredentials = false
            }
            if ('responseType' in xhr && supportsBlob) {
                xhr.responseType = 'blob'
            }
            request.headers.forEach(function(value, name) {
                xhr.setRequestHeader(name, value)
            })

            xhr.send(typeof request._bodyInit === 'undefined' ? null : request._bodyInit)
        })
    }
    self.fetch.polyfill = true
})(typeof self !== 'undefined' ? self : this)

@evilandfox can you explain a bit more how this fix works?

@evilandfox
Copy link
Author

@evilandfox evilandfox commented Nov 17, 2018

@barrylachapelle That's very simple. It is just the original code for overwriting global fetch function with additional

if ('responseType' in xhr && supportsBlob) {
                xhr.responseType = 'blob'
            }

line of fix. And fetch function uses parseHeaders and supportsBlob out of its body, so we also have to add them.

@bonham000
Copy link

@bonham000 bonham000 commented Nov 27, 2018

@jlsilva10 I used the solution above directly in my code. Use urlToBlob, pass in the uri for your file/document/image, and that will return you a promise which returns a blob for your file/document/image. Then, you can use that blob directly in a file upload using fetch, example:

/**
 * Get file blob using local file URI
 */
const blob = await uriToBlob(uri);

const options = {
  method: "PUT",
  body: blob,
  headers: {
    "Content-Type": "image/jpeg",
  },
};

/**
 * Upload blob to your API endpoint
 */
return fetch("your-api/some-endpoint", options);

@jlsilva10
Copy link

@jlsilva10 jlsilva10 commented Nov 27, 2018

Thanks! Worked like a charm ;)

@pierinho287
Copy link

@pierinho287 pierinho287 commented Nov 27, 2018

Use that urlToBlob, and return this:

Promise {
"_40": 0,
"_55": null,
"_65": 0,
"_72": null,
}

@dani-z
Copy link

@dani-z dani-z commented Nov 27, 2018

That returns a promise, you need to await for it.

@adamhongmy
Copy link

@adamhongmy adamhongmy commented Nov 28, 2018

I think the problem is that whatwg-fetch is not setting the type when building the blob.

this worked for me.

function urlToBlob(url) {
  return new Promise((resolve, reject) => {
      var xhr = new XMLHttpRequest();
      xhr.onerror = reject;
      xhr.onreadystatechange = () => {
          if (xhr.readyState === 4) {
              resolve(xhr.response);
          }
      };
      xhr.open('GET', url);
      xhr.responseType = 'blob'; // convert type
      xhr.send();
  })
}

This has to be in the sample code. It took 2 days to figure out the issue.

@tiagodprovenzano
Copy link

@tiagodprovenzano tiagodprovenzano commented Jan 16, 2019

@barrylachapelle That's very simple. It is just the original code for overwriting global fetch function with additional

if ('responseType' in xhr && supportsBlob) {
                xhr.responseType = 'blob'
            }

line of fix. And fetch function uses parseHeaders and supportsBlob out of its body, so we also have to add them.

Can you tell what file should we edit, please?

@EnginYilmaz
Copy link

@EnginYilmaz EnginYilmaz commented Jan 28, 2019

@barrylachapelle That's very simple. It is just the original code for overwriting global fetch function with additional

if ('responseType' in xhr && supportsBlob) {
                xhr.responseType = 'blob'
            }

line of fix. And fetch function uses parseHeaders and supportsBlob out of its body, so we also have to add them.

Can you tell what file should we edit, please?

I guess this one /home/you/yourprojectfolder/node_modules/react-native/Libraries/vendor/core/whatwg-fetch.js

@EnginYilmaz
Copy link

@EnginYilmaz EnginYilmaz commented Jan 28, 2019

I cannot patch the whatwg-fetch.js correctly I am getting this.initBody is not a function error please someone share the full code.

@farzd
Copy link

@farzd farzd commented Jan 29, 2019

@EnginYilmaz just use yonahforst code above

@EnginYilmaz
Copy link

@EnginYilmaz EnginYilmaz commented Jan 29, 2019

@EnginYilmaz just use yonahforst code above

In my situation I am not using GET or PUT just URL for the fetch function for example

  onMessagePress() {
...
    this.setState({ error: '', loading: true, loadingSendingMessage: true });
    myURL = 'https://www.somedomain.com:443/send_message.php' + '?message=' + this.state.bodymessage + '&senderid=' + this.state.email + '&receipentid=' + this.props.navigation.getParam('email');
    return fetch(myURL)
      .then((response) => response.json())
      .then((responseJson) => {
        if (this._mounted) {
          this.setState({ error: responseJson.success });
        }
        if (responseJson.success == true) {
          if (this._mounted) {
            this.setState({ error: "Successfully sent message", loadingSendingMessage: false })
          }
        } else {
          if (this._mounted) {
            this.setState({ error: responseJson.success })
          }
        }
      })
  }

@jrnk
Copy link

@jrnk jrnk commented Jan 29, 2019

@EnginYilmaz same thing, just use the code from yonahforst and do urlToBlob(myURL) instead of fetch(myURL)

@EnginYilmaz
Copy link

@EnginYilmaz EnginYilmaz commented Jan 29, 2019

@EnginYilmaz same thing, just use the code from yonahforst and do urlToBlob(myURL) instead of fetch(myURL)

@jrnk I tried but function never finishes loading and getting warning message

Possible Unhandled Promise Rejection (id: 0): TypeError:response.json is not a function(In 'response.json()', response.json is undefined

@farzd
Copy link

@farzd farzd commented Jan 30, 2019

@EnginYilmaz how are you using it ? please post your code

this should work =


function urlToBlob(url) {
  return new Promise((resolve, reject) => {
      var xhr = new XMLHttpRequest();
      xhr.onerror = reject;
      xhr.onreadystatechange = () => {
          if (xhr.readyState === 4) {
              resolve(xhr.response);
          }
      };
      xhr.open('GET', url);
      xhr.responseType = 'blob'; // convert type
      xhr.send();
  })
}

//inside async function
try {
    const response = await urlToBlob(imageUrl)
    await fetch(url, { method: 'PUT', body: response })
} catch (e) {
 console.log('error is:', e);
}

@EnginYilmaz
Copy link

@EnginYilmaz EnginYilmaz commented Jan 30, 2019

I am getting Network request failed 504:29 error message but not using local or remote image so no image URL. I am using it as #13 (comment)

@EnginYilmaz
Copy link

@EnginYilmaz EnginYilmaz commented Feb 2, 2019

I think it is better not to use fetch anywhere I will have to change all the code to XMLHttpRequest on each scene. I have fetch function nearly on 20 pages in total! I hope this will help anyone consider to use fetch in their project.

@farzd
Copy link

@farzd farzd commented Feb 2, 2019

@EnginYilmaz surely you can just write a fetch function and call it in your 20 pages, it will be a simple find and search ?

@EnginYilmaz
Copy link

@EnginYilmaz EnginYilmaz commented Feb 2, 2019

@farzd I have lots of codes like

fetch('http://example.com/movies.json')
  .then(function(response) {
    return response.json();
  })
  .then(function(myJson) {
    console.log(JSON.stringify(myJson));
  });

What will happen to after .then I need to write them from scratch.

@EnginYilmaz
Copy link

@EnginYilmaz EnginYilmaz commented Feb 2, 2019

Besides, I afroid getting same error message after getting away from fetch

@farzd
Copy link

@farzd farzd commented Feb 6, 2019

@EnginYilmaz I think you're having a different issue, this issue is about uploading an image with the fetch module.
Can you post the URL you're trying to interact with and the params required?

You also dont have a catch in your fetch, use a catch and post the error you're getting

@thekrol01
Copy link

@thekrol01 thekrol01 commented Feb 13, 2019

Does anyone know if fetch is already fixed in sdk32? because XMLHttpRequest() is unfortunately very slow.

@AllAheadFull
Copy link

@AllAheadFull AllAheadFull commented Feb 16, 2019

Finding and reading this thread after at least 60 minutes of wasted work. Thanks so much for the help!

@raRaRa
Copy link

@raRaRa raRaRa commented Feb 20, 2020

Anyone else having trouble getting the blob of a large file, e.g. video file that is over 500 MB in size?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests