RonRadtke / react-native-blob-util

A project committed to making file access and data transfer easier, efficient for React Native developers.
MIT License
773 stars 132 forks source link

Android response info error #261

Closed MuratAkbaba006 closed 1 year ago

MuratAkbaba006 commented 1 year ago

Hello, in android app when I fetched a file, respInfo don't includes status etc. information. its seems like this. "respInfo": {"rnfbEncode": "path"}

RonRadtke commented 1 year ago

Which version are you using? And please a little snippet of your code so we know ehst exactly you're doing

alelaru commented 1 year ago

@MuratAkbaba006 you do not understand it because it is an error of the package.

"react-native": "0.71.4",
"react-native-blob-util": "0.18.3",
"react": "18.2.0",

@RonRadtke the problem is that when installing the packages and running them into the android device sometimes .fetch() will return the correct object with all the information inside and sometimes it will return the object @MuratAkbaba006 shows.

In my case i make a post request to get some data and it will download the file properly but the object res.info() its empty and i also cannot the progress wont log the progress as if it was not called, maybe it is the same error. Ive reinstalled the package and by chance sometimes it works and sometimes it doesn't this error was found previously as res.info() returns undefined

My call looks like this, nothing complicated:

       await ReactNativeBlobUtil.config({
      path,
      fileCache: true,
    })
      .fetch(
        'POST',
        ....
      )
      .progress({ count: 25 }, (received, total) => {
        console.log('\n -------- > progress', {
          received,
          total,
        });
      })
      .then(res => {
        attachmentsUpdated = true;
        if (res.info().status === 200) {
          console.log(`Sound file name: ${originalFilename} downloaded`);
        } else {
          console.log('Unknowkn', res.info().status);
        }
      });
RonRadtke commented 1 year ago

@alelaru are you able to reproduce this behavior? Does in addition occour any error?

MuratAkbaba006 commented 1 year ago

@RonRadtke I tried 0.17.2, 0.17.3, 0.18.3 versions. all of them same result.

here is my code;

Screen Shot 2023-06-22 at 10 31 32 Screen Shot 2023-06-22 at 10 33 43
ammarahm-ed commented 1 year ago

I am getting the same issue on iOS in release builds on file upload.

The response doesn't include text or status and no progress. Just this:

{"rnfbEncode": "utf8"}

Here's the upload code, this works in debug but not in release build:

let request = RNFetchBlob.config({
      IOSBackgroundTask: !globalThis["IS_SHARE_EXTENSION"]
    })
      .fetch(
        "PUT",
        uploadUrl,
        {
          "content-type": ""
        },
        RNFetchBlob.wrap(uploadFilePath)
      )
      .uploadProgress((sent, total) => {
        useAttachmentStore
          .getState()
          .setProgress(sent, total, filename, 0, "upload");
        DatabaseLogger.info(`uploading file: ${sent}/${total}`);
      });
    cancelToken.cancel = request.cancel;
    let response = await request;

    let status = response.info().status;
    let text = await response.text();

The request does get sent to the server because if i disable internet, i get a proper error thrown. I have confirmed that the file exists at the upload path.

Version: 0.17.3

Edit: This is inconsistent. doesn't happen always.

Edit: Stepping through the code, I found out that req is nil in sendRequest on iOS: Screenshot 2023-07-12 at 11 25 52 AM

MuratAkbaba006 commented 1 year ago

Additionally, if the file does not exist or there is some other error on backend side. catch block and timeout duration doesn't work. @RonRadtke

ammarahm-ed commented 1 year ago

I was on v0.17.3. Upgrading to 0.18.3 has fixed the issue for me on iOS. As i tracked it down DeviceEventEmitter not receiving any events. The 0.18.3 replaces that with NativeEventEmitter which fixes the problem. As you are facing the issue on android, the probable cause can be something similar because:

If the below event doesn't fire before fetchBlob method callback is called, the respInfo includes just rnfbEncode:"type of encoding"

stateEvent = eventEmitter.addListener('ReactNativeBlobUtilState', (e) => {
            if (typeof e === 'string') e = JSON.parse(e);
            if (e.taskId === taskId)
                respInfo = e;
            promise.onStateChange && promise.onStateChange(e);
        });

And just to be 100% sure I have added below code to ensure I get the response status code in any case the events don't fire: Screenshot 2023-07-12 at 3 22 09 PM and made slight change to fetch.js:

if (respInfo.status === undefined || respInfo.status === null) {
                    respInfo.status = resp.status
                }
                resolve(new FetchBlobResponse(taskId, respInfo, data));

If it's still happening on android, my guess is event is not fired on time or not fired at all during fetch request sometimes.

Here's the final patch for android & ios I am using now just to be safe:

diff --git a/node_modules/react-native-blob-util/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilReq.java b/node_modules/react-native-blob-util/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilReq.java
index 9aee829..87124b3 100644
--- a/node_modules/react-native-blob-util/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilReq.java
+++ b/node_modules/react-native-blob-util/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilReq.java
@@ -634,7 +634,9 @@ public class ReactNativeBlobUtilReq extends BroadcastReceiver implements Runnabl
      */
     private void done(Response resp) {
         boolean isBlobResp = isBlobResponse(resp);
-        emitStateEvent(getResponseInfo(resp, isBlobResp));
+        WritableMap map = getResponseInfo(resp,isBlobResp);
+        emitStateEvent(getResponseInfo(resp,isBlobResp));
+
         switch (responseType) {
             case KeepInMemory:
                 try {
@@ -652,7 +654,7 @@ public class ReactNativeBlobUtilReq extends BroadcastReceiver implements Runnabl
                         ins.close();
                         os.flush();
                         os.close();
-                        invoke_callback(null, ReactNativeBlobUtilConst.RNFB_RESPONSE_PATH, dest);
+                        invoke_callback(null, ReactNativeBlobUtilConst.RNFB_RESPONSE_PATH, dest, map);
                     }
                     // response data directly pass to JS context as string.
                     else {
@@ -674,11 +676,11 @@ public class ReactNativeBlobUtilReq extends BroadcastReceiver implements Runnabl
                                 invoke_callback("Error from file transformer:" + e.getLocalizedMessage(), null);
                                 return;
                             }
-                            invoke_callback(null, ReactNativeBlobUtilConst.RNFB_RESPONSE_PATH, this.destPath);
+                            invoke_callback(null, ReactNativeBlobUtilConst.RNFB_RESPONSE_PATH, this.destPath,map);
                             return;
                         }
                         if (responseFormat == ResponseFormat.BASE64) {
-                            invoke_callback(null, ReactNativeBlobUtilConst.RNFB_RESPONSE_BASE64, android.util.Base64.encodeToString(b, Base64.NO_WRAP));
+                            invoke_callback(null, ReactNativeBlobUtilConst.RNFB_RESPONSE_BASE64, android.util.Base64.encodeToString(b, Base64.NO_WRAP),map);
                             return;
                         }
                         try {
@@ -688,21 +690,21 @@ public class ReactNativeBlobUtilReq extends BroadcastReceiver implements Runnabl
                             decoder.decode(ByteBuffer.wrap(b));
                             // If the data contains invalid characters the following lines will be skipped.
                             String utf8 = new String(b, charSet);
-                            invoke_callback(null, ReactNativeBlobUtilConst.RNFB_RESPONSE_UTF8, utf8);
+                            invoke_callback(null, ReactNativeBlobUtilConst.RNFB_RESPONSE_UTF8, utf8,map);
                         }
                         // This usually means the data contains invalid unicode characters but still valid data,
                         // it's binary data, so send it as a normal string
                         catch (CharacterCodingException ignored) {
                             if (responseFormat == ResponseFormat.UTF8) {
                                 String utf8 = new String(b);
-                                invoke_callback(null, ReactNativeBlobUtilConst.RNFB_RESPONSE_UTF8, utf8);
+                                invoke_callback(null, ReactNativeBlobUtilConst.RNFB_RESPONSE_UTF8, utf8,map);
                             } else {
-                                invoke_callback(null, ReactNativeBlobUtilConst.RNFB_RESPONSE_BASE64, android.util.Base64.encodeToString(b, Base64.NO_WRAP));
+                                invoke_callback(null, ReactNativeBlobUtilConst.RNFB_RESPONSE_BASE64, android.util.Base64.encodeToString(b, Base64.NO_WRAP),map);
                             }
                         }
                     }
                 } catch (IOException e) {
-                    invoke_callback("ReactNativeBlobUtil failed to encode response data to BASE64 string.", null);
+                    invoke_callback("ReactNativeBlobUtil failed to encode response data to BASE64 string.", null,map);
                 }
                 break;
             case FileStorage:
@@ -742,18 +744,18 @@ public class ReactNativeBlobUtilReq extends BroadcastReceiver implements Runnabl
                 }

                 if (ReactNativeBlobUtilFileResp != null && !ReactNativeBlobUtilFileResp.isDownloadComplete()) {
-                    invoke_callback("Download interrupted.", null);
+                    invoke_callback("Download interrupted.", null,map);
                 } else {
                     this.destPath = this.destPath.replace("?append=true", "");
-                    invoke_callback(null, ReactNativeBlobUtilConst.RNFB_RESPONSE_PATH, this.destPath);
+                    invoke_callback(null, ReactNativeBlobUtilConst.RNFB_RESPONSE_PATH, this.destPath,map);
                 }

                 break;
             default:
                 try {
-                    invoke_callback(null, ReactNativeBlobUtilConst.RNFB_RESPONSE_UTF8, new String(resp.body().bytes(), "UTF-8"));
+                    invoke_callback(null, ReactNativeBlobUtilConst.RNFB_RESPONSE_UTF8, new String(resp.body().bytes(), "UTF-8"),map);
                 } catch (IOException e) {
-                    invoke_callback("ReactNativeBlobUtil failed to encode response data to UTF8 string.", null);
+                    invoke_callback("ReactNativeBlobUtil failed to encode response data to UTF8 string.", null,map);
                 }
                 break;
         }
diff --git a/node_modules/react-native-blob-util/fetch.js b/node_modules/react-native-blob-util/fetch.js
index 97e5263..45c086c 100644
--- a/node_modules/react-native-blob-util/fetch.js
+++ b/node_modules/react-native-blob-util/fetch.js
@@ -244,7 +244,7 @@ export function fetch(...args: any): Promise {
          *                  dose the response data presents.
          * @param data {string} Response data or its reference.
          */
-        req(options, taskId, method, url, headers || {}, body, (err, rawType, data) => {
+        req(options, taskId, method, url, headers || {}, body, (err, rawType, data, responseInfo) => {

             // task done, remove event listeners
             subscription.remove();
@@ -270,6 +270,9 @@ export function fetch(...args: any): Promise {
                         fs.session(options.session).add(data);
                 }
                 respInfo.rnfbEncode = rawType;
+                if (respInfo.status === undefined || respInfo.status === null) {
+                    respInfo.status = responseInfo?.status
+                }
                 resolve(new FetchBlobResponse(taskId, respInfo, data));
             }

diff --git a/node_modules/react-native-blob-util/ios/ReactNativeBlobUtilRequest.mm b/node_modules/react-native-blob-util/ios/ReactNativeBlobUtilRequest.mm
index d4e468a..25b8d81 100644
--- a/node_modules/react-native-blob-util/ios/ReactNativeBlobUtilRequest.mm
+++ b/node_modules/react-native-blob-util/ios/ReactNativeBlobUtilRequest.mm
@@ -438,13 +438,20 @@ - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCom
         }
     }

+    NSHTTPURLResponse *response = (NSHTTPURLResponse *) [task response];
+    

     callback(@[
                errMsg ?: [NSNull null],
                rnfbRespType ?: @"",
-               respStr ?: [NSNull null]
+               respStr ?: [NSNull null],
+                 @{
+                     @"status": [NSNumber numberWithInteger:[response statusCode]]
+                 }
                ]);

+    
+
     respData = nil;
     receivedBytes = 0;
     [session finishTasksAndInvalidate];
chubo274 commented 1 year ago

Hello, in android app when I fetched a file, respInfo don't includes status etc. information. its seems like this. "respInfo": {"rnfbEncode": "path"}

I tried 0.17.1, 0.17.3, 0.18.3 versions. but got same issue. have you solved it, pls help me :(

RonRadtke commented 1 year ago

Thank you for the patch I will take a look at and see if ai can get it integrated soon

NishilE commented 1 year ago

Hello, I'm still facing the issue with version 0.19.4. Unable to retrieve the response code or status code or the error messages or the success messages from the responses while downloading the PDF files.

ChrisZilch commented 1 month ago

We are still facing this issue on Android using RN 0.73.8, having tested on 0.19.4, 0.19.5, 0.19.8 and 0.19.11.

Here is a snippet of our code when downloading a PDF:

const configOptions: ReactNativeBlobUtilConfig = Platform.select({
  ios: { ... },
  android: {
    fileCache: true,
    appendExt: "pdf",
    addAndroidDownloads: {
      useDownloadManager: true,
      mime: "application/pdf",
      title,
      notification: false,
      path,
    },
  },
});

ReactNativeBlobUtil.config(configOptions)
  .fetch("GET", url, {
    Authorization: ...,
  })
  .then((resp) => {
    // do something with the response status
    console.log(resp.info());
  })

The download is successful and we can display the PDF, but when we try to read the response info all we get is

{"rnfbEncode": "path"}

It works correctly on iOS.

Any ideas why we get this issue even on the latest version?