从 Laravel 服务器下载图像到 React Native?

时间:2021-03-15 13:05:23

标签: laravel react-native axios

我希望将存储在服务器上的图像下载到我的 React Native 应用程序中。

我有一个看起来像这样的函数:

public function image(Request $request, $id)
{
    $company = Company::find($id);
    $filePath = storage_path() . '/app/' . $company->image;
    
    return response()->file($filePath);
}

当我尝试以下函数时,它返回了我无法在应用程序中读取的任何内容:

setCompany = async () => {
let company = await AsyncStorage.getItem('currentCompany');

company = JSON.parse(company);

if (company.image !== null) {
  let image = await getCompanyPicture({company_id: company.id});

  console.log('Here: ', image); 
  // This is blank, react native returns a warning about data not being of a readable type
}

this.setState({company});

};

我可以使用这种方法在 base_64 中获取图像:

public function image(Request $request, $id)
{
    $company = Company::find($id);
    $file_path = storage_path('/app/' . $company->image);

    if (file_exists($file_path)) {
        $fileData = file_get_contents($file_path);
        $fileEncode = base64_encode($fileData);

        return response()->json(['status' => 'success', 'data' => ['file' => $fileEncode, 'file_path' => $file_path]]);
    }

    return response()->json(['status' => 'failure', 'data' => ['file' => null, 'file_path' => $file_path]]);
}

这里也是我的 Axios 方法,以防万一:

export const sendRequest = async (url, data, token, method) => {
  let headers = {
    'Content-Type': 'application/json',
    'Access-Control-Allow-Origin': '*',
    'Access-Control-Allow-Method': 'POST, GET, DELETE, PUT',
  };

  if (typeof token !== 'undefined' && token !== 'undefined' && token.length) {
    headers.Authorization = 'Bearer ' + token;
  }

  if (method === 'get' && data) {
    url +=
      '?' +
      Object.keys(data)
        .map((value) => {
          return value + '=' + data[value];
        })
        .join('&');
    data = null;
  }

  return await axios({
    headers: headers,
    method: method ? method : 'post',
    url: url,
    data: data,
  })
    .then((response) => {
      return response;
    })
    .then((json) => {
      return json.data;
    })
    .catch((error) => {
      console.error(error);

      if (
        error.message !== 'Network Error' &&
        error.response.status !== 500 &&
        error.response.status !== 413
      ) {
        return error.response.data;
      } else if (error.message === 'Network Error') {
        return {
          status: 'error',
          message: 'Unable to connect to server',
        };
      } else if (error.response.status === 500) {
        return {
          status: 'error',
          message: 'Internal Server Error',
        };
      } else if (error.response.status === 413) {
        return {
          status: 'error',
          message: 'The file(s) size is too large',
        };
      } else {
        return {
          status: 'error',
          message: error.message,
        };
      }
    });
};

如果有人可以评论使用 base_64 而不是直接下载文件对性能的影响,那也会有帮助

但最终我想要一个解决方案来处理 Laravel response()->file() 如果可能的话(如果 base_64 效率较低,我会使用它)

2 个答案:

答案 0 :(得分:0)

我不确定 RN 代码语法,但我已经准备好使用 jQuery+poorJS 的代码,如下所示:

$.ajax({
    url: "load-image-url", // URL FOR GET REQUEST
    cache:false,
    xhr: function() { // ACTUALLY THIS PART CAN BE USED AND CUSTOMIZED BY YOU
        let xhr = new XMLHttpRequest();
        xhr.responseType= 'blob'
        return xhr;
    },
    success: function(data) {
        let url = window.URL || window.webkitURL;
        $('#image').attr('src', url.createObjectURL(data));
    },
    error: function(err) {
        // console.log(err);
    }
}).fail(function() {
    $('#ss_product_image').attr('src', "default-image-url.jpg");
});

在我的示例中,我使用了 GET 请求(但您可以尝试修改它并根据需要进行测试,老实说 IDK)。

这是后端部分:

public function image(Request $request, $id)
{
    // HERE YOU NEED TO GET YOUR IMAGE (using $id or/and $request params) CONTENT FROM SOMEWHERE YOU WANT
    $content = <CONTENT>;

    return response()->make($content, 200, [
        'Content-Type' => (new \finfo(FILEINFO_MIME))->buffer($content),
        'Content-length' => strlen($content),
    ]);
}

答案 1 :(得分:0)

我能够通过使用 rn-blob-fetch 解决这个问题。

文件被下载到临时缓存中,然后可以访问该缓存以进行预览和保存。

这是我现在的功能:

  downloadFiles = async (isReply) => {
    let {enquiry, reply} = this.state;

    this.setState({isLoading: true});

    const token = await AsyncStorage.getItem('userToken');

    let filePaths = [];
    let fileCount = 0;

    let files = enquiry.files;
    if (isReply) {
      files = reply.files;
    }

    const dirToSave =
      Platform.OS == 'ios'
        ? RNFetchBlob.fs.dirs.DocumentDir
        : RNFetchBlob.fs.dirs.DownloadDir;

    new Promise((resolve, reject) => {
      for (var i = 0; i < files.length; i++) {
        var id = files[i].file_id;
        var name = files[i].file.file_name;
        var ext = extension(name);

        const configOptions = Platform.select({
          ios: {
            appendExt: ext,
            fileCache: true,
            title: name,
            path: `${dirToSave}/${name}`,
          },
          android: {
            useDownloadManager: true,
            notification: true,
            mediaScannable: true,
            fileCache: true,
            title: name,
            path: `${dirToSave}/${name}`,
          },
        });

        var mime = content(ext);
        let headers = {
          'Content-Type': mime,
          'Access-Control-Allow-Origin': '*',
          'Access-Control-Allow-Method': 'POST, GET, DELETE, PUT',
          Authorization: 'Bearer ' + token,
        };

        RNFetchBlob.config(configOptions)
          .fetch('GET', BASE_API + '/enquiries/files/download/' + id, headers)
          .then(async (response) => {
            RNFetchBlob.fs.writeFile(
              configOptions.path,
              response.data,
              'base64',
            );

            filePaths.push({
              title: configOptions.title,
              path: configOptions.path,
              ext: extension(configOptions.title),
              mime,
            });

            fileCount++;
            if (fileCount >= files.length) {
              resolve('Download Successful!');
            }
          })
          .catch((error) => {
            console.log('File Download Error: ', error.message);
            reject('Download Failed');
          });
      }
    })
      .then((data) => {
        this.setState({isLoading: false, filePaths});
      })
      .catch((error) => {
        console.log('Download Promise Error: ', error);
        this.setState({isLoading: false});
      });
  };

  previewDocument = (id) => {
    let {filePaths} = this.state;

    if (Platform.OS == 'ios') {
      RNFetchBlob.ios.openDocument(filePaths[id].path);
    } else if (Platform.OS == 'android') {
      RNFetchBlob.android.actionViewIntent(
        filePaths[id].path,
        filePaths[id].mime,
      );
    }
  };