Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

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

Comments

@evilandfox
Copy link

@evilandfox evilandfox commented Nov 7, 2018

Have anyone same problem?

@devjv

This comment has been minimized.

Copy link

@devjv devjv commented Nov 8, 2018

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

@evilandfox

This comment has been minimized.

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

This comment has been minimized.

Copy link
Author

@evilandfox evilandfox commented Nov 8, 2018

@devjv

This comment has been minimized.

Copy link

@devjv devjv commented Nov 8, 2018

Thank you so much for that!

@yonahforst

This comment has been minimized.

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

This comment has been minimized.

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

This comment has been minimized.

Copy link

@farzd farzd commented Nov 12, 2018

@yonahforst thanks!!

@barrylachapelle

This comment has been minimized.

Copy link

@barrylachapelle barrylachapelle commented Nov 12, 2018

You the man @yonahforst

@bonham000

This comment has been minimized.

Copy link

@bonham000 bonham000 commented Nov 16, 2018

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

@barrylachapelle

This comment has been minimized.

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

This comment has been minimized.

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

This comment has been minimized.

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

This comment has been minimized.

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

This comment has been minimized.

Copy link

@jlsilva10 jlsilva10 commented Nov 27, 2018

Thanks! Worked like a charm ;)

@pierinho287

This comment has been minimized.

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

This comment has been minimized.

Copy link

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

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

@adamhongmy

This comment has been minimized.

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

This comment has been minimized.

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

This comment has been minimized.

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

This comment has been minimized.

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

This comment has been minimized.

Copy link

@farzd farzd commented Jan 29, 2019

@EnginYilmaz just use yonahforst code above

@EnginYilmaz

This comment has been minimized.

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

This comment has been minimized.

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

This comment has been minimized.

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

This comment has been minimized.

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

This comment has been minimized.

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

This comment has been minimized.

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

This comment has been minimized.

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

This comment has been minimized.

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

This comment has been minimized.

Copy link

@EnginYilmaz EnginYilmaz commented Feb 2, 2019

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

@farzd

This comment has been minimized.

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

This comment has been minimized.

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

This comment has been minimized.

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!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
You can’t perform that action at this time.