浏览代码

Merge pull request #2291 from transloadit/more-network-errors

Transloadit: Add NetworkError handling
Artur Paikin 4 年之前
父节点
当前提交
dddb2a1f43

+ 4 - 25
packages/@uppy/companion-client/src/RequestClient.js

@@ -1,7 +1,7 @@
 'use strict'
 
 const AuthError = require('./AuthError')
-const NetworkError = require('@uppy/utils/lib/NetworkError')
+const fetchWithNetworkError = require('@uppy/utils/lib/fetchWithNetworkError')
 
 // Remove the trailing slash so we can always safely append /xyz.
 function stripSlash (url) {
@@ -134,18 +134,11 @@ module.exports = class RequestClient {
   get (path, skipPostResponse) {
     return new Promise((resolve, reject) => {
       this.preflightAndHeaders(path).then((headers) => {
-        fetch(this._getUrl(path), {
+        fetchWithNetworkError(this._getUrl(path), {
           method: 'get',
           headers: headers,
           credentials: 'same-origin'
         })
-          .catch((err) => {
-            if (err.name === 'AbortError') {
-              throw err
-            } else {
-              throw new NetworkError(err)
-            }
-          })
           .then(this._getPostResponseFunc(skipPostResponse))
           .then((res) => this._json(res).then(resolve))
           .catch((err) => {
@@ -159,19 +152,12 @@ module.exports = class RequestClient {
   post (path, data, skipPostResponse) {
     return new Promise((resolve, reject) => {
       this.preflightAndHeaders(path).then((headers) => {
-        fetch(this._getUrl(path), {
+        fetchWithNetworkError(this._getUrl(path), {
           method: 'post',
           headers: headers,
           credentials: 'same-origin',
           body: JSON.stringify(data)
         })
-          .catch((err) => {
-            if (err.name === 'AbortError') {
-              throw err
-            } else {
-              throw new NetworkError(err)
-            }
-          })
           .then(this._getPostResponseFunc(skipPostResponse))
           .then((res) => this._json(res).then(resolve))
           .catch((err) => {
@@ -185,19 +171,12 @@ module.exports = class RequestClient {
   delete (path, data, skipPostResponse) {
     return new Promise((resolve, reject) => {
       this.preflightAndHeaders(path).then((headers) => {
-        fetch(`${this.hostname}/${path}`, {
+        fetchWithNetworkError(`${this.hostname}/${path}`, {
           method: 'delete',
           headers: headers,
           credentials: 'same-origin',
           body: data ? JSON.stringify(data) : null
         })
-          .catch((err) => {
-            if (err.name === 'AbortError') {
-              throw err
-            } else {
-              throw new NetworkError(err)
-            }
-          })
           .then(this._getPostResponseFunc(skipPostResponse))
           .then((res) => this._json(res).then(resolve))
           .catch((err) => {

+ 10 - 1
packages/@uppy/transloadit/src/Assembly.js

@@ -2,6 +2,8 @@ const io = requireSocketIo
 const Emitter = require('component-emitter')
 const has = require('@uppy/utils/lib/hasProperty')
 const parseUrl = require('./parseUrl')
+const NetworkError = require('@uppy/utils/lib/NetworkError')
+const fetchWithNetworkError = require('@uppy/utils/lib/fetchWithNetworkError')
 
 // Lazy load socket.io to avoid a console error
 // in IE 10 when the Transloadit plugin is not used.
@@ -78,6 +80,12 @@ class TransloaditAssembly extends Emitter {
 
       this.emit('connect')
     })
+
+    socket.on('connect_failed', () => {
+      this._onError(new NetworkError('Transloadit Socket.io connection error'))
+      this.socket = null
+    })
+
     socket.on('error', () => {
       socket.disconnect()
       this.socket = null
@@ -143,7 +151,7 @@ class TransloaditAssembly extends Emitter {
    * 'status'.
    */
   _fetchStatus ({ diff = true } = {}) {
-    return fetch(this.status.assembly_ssl_url)
+    return fetchWithNetworkError(this.status.assembly_ssl_url)
       .then((response) => response.json())
       .then((status) => {
         // Avoid updating if we closed during this request's lifetime.
@@ -156,6 +164,7 @@ class TransloaditAssembly extends Emitter {
           this.status = status
         }
       })
+      .catch((err) => this._onError(err))
   }
 
   update () {

+ 23 - 18
packages/@uppy/transloadit/src/Client.js

@@ -1,3 +1,5 @@
+const fetchWithNetworkError = require('@uppy/utils/lib/fetchWithNetworkError')
+
 /**
  * A Barebones HTTP API client for Transloadit.
  */
@@ -38,23 +40,25 @@ module.exports = class Client {
     data.append('num_expected_upload_files', expectedFiles)
 
     const url = `${this.opts.service}/assemblies`
-    return fetch(url, {
+    return fetchWithNetworkError(url, {
       method: 'post',
       headers: this._headers,
       body: data
-    }).then((response) => response.json()).then((assembly) => {
-      if (assembly.error) {
-        const error = new Error(assembly.error)
-        error.details = assembly.message
-        error.assembly = assembly
-        if (assembly.assembly_id) {
-          error.details += ' ' + `Assembly ID: ${assembly.assembly_id}`
+    })
+      .then((response) => response.json()).then((assembly) => {
+        if (assembly.error) {
+          const error = new Error(assembly.error)
+          error.details = assembly.message
+          error.assembly = assembly
+          if (assembly.assembly_id) {
+            error.details += ' ' + `Assembly ID: ${assembly.assembly_id}`
+          }
+          throw error
         }
-        throw error
-      }
 
-      return assembly
-    }).catch((err) => this._reportError(err, { url, type: 'API_ERROR' }))
+        return assembly
+      })
+      .catch((err) => this._reportError(err, { url, type: 'API_ERROR' }))
   }
 
   /**
@@ -66,7 +70,7 @@ module.exports = class Client {
   reserveFile (assembly, file) {
     const size = encodeURIComponent(file.size)
     const url = `${assembly.assembly_ssl_url}/reserve_file?size=${size}`
-    return fetch(url, { method: 'post', headers: this._headers })
+    return fetchWithNetworkError(url, { method: 'post', headers: this._headers })
       .then((response) => response.json())
       .catch((err) => this._reportError(err, { assembly, file, url, type: 'API_ERROR' }))
   }
@@ -88,7 +92,7 @@ module.exports = class Client {
 
     const qs = `size=${size}&filename=${filename}&fieldname=${fieldname}&s3Url=${uploadUrl}`
     const url = `${assembly.assembly_ssl_url}/add_file?${qs}`
-    return fetch(url, { method: 'post', headers: this._headers })
+    return fetchWithNetworkError(url, { method: 'post', headers: this._headers })
       .then((response) => response.json())
       .catch((err) => this._reportError(err, { assembly, file, url, type: 'API_ERROR' }))
   }
@@ -100,7 +104,7 @@ module.exports = class Client {
    */
   cancelAssembly (assembly) {
     const url = assembly.assembly_ssl_url
-    return fetch(url, { method: 'delete', headers: this._headers })
+    return fetchWithNetworkError(url, { method: 'delete', headers: this._headers })
       .then((response) => response.json())
       .catch((err) => this._reportError(err, { url, type: 'API_ERROR' }))
   }
@@ -111,7 +115,7 @@ module.exports = class Client {
    * @param {string} url The status endpoint of the assembly.
    */
   getAssemblyStatus (url) {
-    return fetch(url, { headers: this._headers })
+    return fetchWithNetworkError(url, { headers: this._headers })
       .then((response) => response.json())
       .catch((err) => this._reportError(err, { url, type: 'STATUS_ERROR' }))
   }
@@ -121,7 +125,7 @@ module.exports = class Client {
       ? `${err.message} (${err.details})`
       : err.message
 
-    return fetch('https://status.transloadit.com/client_error', {
+    return fetchWithNetworkError('https://status.transloadit.com/client_error', {
       method: 'post',
       body: JSON.stringify({
         endpoint,
@@ -131,7 +135,8 @@ module.exports = class Client {
         client: this.opts.client,
         error: message
       })
-    }).then((response) => response.json())
+    })
+      .then((response) => response.json())
   }
 
   _reportError (err, params) {

+ 15 - 0
packages/@uppy/utils/src/fetchWithNetworkError.js

@@ -0,0 +1,15 @@
+const NetworkError = require('@uppy/utils/lib/NetworkError')
+
+/**
+ * Wrapper around window.fetch that throws a NetworkError when appropriate
+ */
+module.exports = function fetchWithNetworkError (...options) {
+  return fetch(...options)
+    .catch((err) => {
+      if (err.name === 'AbortError') {
+        throw err
+      } else {
+        throw new NetworkError(err)
+      }
+    })
+}

+ 12 - 0
website/src/docs/uppy.md

@@ -753,6 +753,18 @@ uppy.on('upload-error', (file, error, response) => {
 })
 ```
 
+If the error is related to network conditions — endpoint unreachable due to firewall or ISP blockage, for instance — the error will have `error.isNetworkError` property set to `true`. Here’s how you can check for network errors:
+
+``` javascript
+uppy.on('upload-error', (file, error, response) => {
+  if (error.isNetworkError) {
+    // Let your users know that file upload could have failed
+    // due to firewall or ISP issues
+    alertUserAboutPossibleFirewallOrISPIssues(error)
+  }
+})
+```
+
 ### `upload-retry`
 
 Fired when an upload has been retried (after an error, for example):