2013-08-15 19 views
13

Tôi có một angularJs "hủy" $http gọi như thế này:Xác định nếu AJAX bị hủy hoặc có một lỗi trong AngularJs chặn

var defer = $q.defer() 
$http.post("http://example.com/someUrl", {some: "data"}, {timeout: defer.promise}) 

Và tôi hủy rằng yêu cầu ajax sử dụng defer.resolve() vì một số logic đòi hỏi nó.


Một số nơi khác trong mã của tôi, tôi có một iterceptor như thế này:

angular.module("services.interceptor", arguments).config(function($httpProvider) { 
    $httpProvider.interceptors.push(function($q) { 
     return { 
      responseError: function(rejection) { 
      if(rejection.status == 0) { 
       alert("check your connection"); 
      } 
      return $q.reject(rejection); 
     } 
     }; 
    }); 
    }); 
}); 

Vấn đề:

Nếu có một kết nối vấn đề Internet , ajax thất bại với trạng thái 0 và thiết bị đánh chặn bắt nó. Nếu ajax bị hủy bỏ bởi lời hứa hết thời gian chờ , ngoài trạng thái cũng là 0 và thiết bị chặn sẽ bắt được.

Tôi không thể tìm hiểu xem nó bị hủy hay gặp lỗi trong trình xử lý responseError.

cách tiếp cận ngây thơ của tôi là để kiểm tra xem thời gian chờ được định nghĩa như thế này:

responseError: function(rejection) { 
    if(rejection.status == 0 && !rejection.config.timeout) { 
    alert("check your connection"); 
    } 
    return $q.reject(rejection); 
} 

Nó chỉ đảm bảo rằng, có một điều kiện thời gian chờ theo yêu cầu đó, không nó không thành công vì nó. Nhưng tốt hơn là không có gì.

Có cách nào thực sự hiệu quả để xác định xem ajax có bị lỗi hoặc bị hủy không?

Tôi đang sử dụng AngularJs 1.1.5

+0

Bạn có thể lấy mã trạng thái HTTP? –

+0

@DavinTryon Trong cả hai trường hợp, hủy bỏ và mã trạng thái lỗi mạng trả về là 0. –

+0

Bắt chính xác vấn đề này vào lúc này (với góc 1.2.0) – Phantomwhale

Trả lời

5

tôi đã kết thúc làm điều này bằng cách sử dụng lá cờ, mà sẽ được kiểm tra trong xử lý lỗi.

Tôi bắt đầu theo lời khuyên vào cuối này AngularJS Github vấn đề: https://github.com/angular/angular.js/issues/1159#issuecomment-25735438

Điều này dẫn tôi để xây dựng một dịch vụ mà sử dụng một lời hứa tự "timeout" cuộc gọi http - như bạn đã làm dưới đây - bằng cách sao chép thư mục được liên kết từ vấn đề đó: http://plnkr.co/edit/P8wKns51GVqw5mwS5l5R?p=preview

Nhưng điều này không hoàn toàn đầy đủ, vì điều này không giải quyết được vấn đề bạn nêu ra; trong quá trình xử lý lỗi, cách xác định xem cuộc gọi có phải là máy chủ chính thức ngừng hoạt động hay hết thời gian chờ hay chỉ đơn giản là thời gian chờ được kích hoạt theo cách thủ công. Cuối cùng, tôi đã phải nhờ đến lưu trữ nó trong một biến khác (tương tự như lời hứa thời gian chờ), có thể được nhìn thấy trong liệng này: http://plnkr.co/edit/BW6Zwu

Phương pháp chính của mã này trông như sau

return function (url) { 
    var cancelQuery = null; 
    var queryCancelled = false; 

    return function runQuery(query) { 
     if (cancelQuery) { 
     queryCancelled = true; 
     cancelQuery.resolve(); 
     } 
     cancelQuery = $q.defer(); 
     return $http. 
     get(url, { params: { query: query }, timeout: cancelQuery.promise }). 
     then(function (response) { 
      cancelQuery = null; 
      return response.data; 
     }, function (error) { 
      if(queryCancelled) { 
      console.log("Request cancelled"); 
      queryCancelled = false; 
      } else { 
      console.log("Actual Error !"); 
      } 
     }); 
    }; 
    }; 

Không quá thanh lịch, nhưng có vẻ như nó hoạt động và tránh bất kỳ điều kiện cuộc đua khó chịu nào từ những gì tôi đã quan sát.

+1

Cảm ơn bạn đã tiếp cận. Tôi đã bọc $ http của tôi và cancelPromise đã cho nếu có lời hứa của tôi và kiểm tra trạng thái của họ như bạn đã làm trong ví dụ của bạn bằng một cờ boolean. Hơn tôi đã thay đổi response.status ban đầu = 0 đến 1 cho các lời hứa bị hủy để hiểu sự khác biệt. Cảm ơn! –

+1

Tôi đã thực hiện điều này một chút thanh lịch (ít nhất là để mắt của riêng tôi) bằng cách thiết lập queryCancelled như là một tài sản của cancelQuery. Cũng có thể tận dụng lợi thế của bản chất của javascript. – Dave

0

Tôi biết câu hỏi đã cũ hơn một chút, nhưng tôi đã tìm ra giải pháp cho cùng một vấn đề.Khác với trong câu trả lời đã được đưa ra tôi không muốn kiểm tra một lá cờ mà tôi đặt cùng một lúc như tôi có thể yêu cầu AJAX. Nó có thể đã là một yêu cầu mới, mà không bị can thiệp.

Vì vậy, tôi đã tìm thấy một giải pháp khác cho tôi. Có lẽ ai đó có thể tận dụng nó, althoug nó không phải là một câu hỏi cập nhật.

Tinh hoa của giải pháp của tôi là, để kiểm tra không chỉ trạng thái. Nếu dữ liệu cũng là null, nó là một yêu cầu cancled.

var defer = $q.defer() 
$http.get("http://example.com/someUrl", {timeout: defer.promise}) 
    .error(function(data, status){ 
     if (data === null && status === 0) { 
      // the request was cancled 
     } 
    }); 
+6

lỗi thời gian chờ do mất kết nối cũng có dữ liệu null và trạng thái 0 ... –

2

Nếu bạn hủy yêu cầu sử dụng timeout, thời gian chờ được liệt kê trong cấu hình phản hồi.

Kiểm tra .config.timeout trong đối tượng trả lời của bạn:

function config($httpProvider) { 

    $httpProvider.interceptors.push(function ($q, $injector) { 
     return { 
      request: function (config) { 
       return config; 
      }, 

      response: function (response) { 
       return response || $q.when(response); 
      }, 

      responseError: function (response) { 
       switch (response.status) { 
        case -1: 
        case 500 : 
        case 501 : 
        case 502 : 
        case 503 : 
        case 504 : 
         // the webapp sometimes aborts network requests. Those that dropped should not be restarted 
         if (response.status === -1 && response.config.timeout) { 
          break; 
         } 
         return retryRequest(response.config, response.status); 
       } 
       // otherwise 
       return $q.reject(response); 
      } 
     }; 
    }); 
} 
+0

Trong trường hợp của tôi cho dù yêu cầu của tôi bị hủy bỏ bởi một thời gian chờ hoặc tôi nhận được 401 từ máy chủ, response.config.timeout được thiết lập và response.status là -1. – user276648

0

Bạn có thể sử dụng (rejection.config.timeout.status = 499!):

...timeout.promise.status = 499; 
...timeout.resolve(); 

responseError: function(rejection) { 
    if(rejection.status == 0 && rejection.config.timeout.status != 499) { 
    alert("check your connection"); 
    } 
    return $q.reject(rejection); 
} 

thay vì:

responseError: function(rejection) { 
    if(rejection.status == 0 && !rejection.config.timeout) { 
    alert("check your connection"); 
    } 
    return $q.reject(rejection); 
} 

Bằng cách này, bạn không cần thêm yêu cầu trang trí.

0

Tôi đã có thể xác định xem yêu cầu đã bị hủy trong Chrome v55 hay chưa bằng cách kiểm tra loại thuộc tính của đối tượng sự kiện toàn cầu dựa vào chuỗi "hủy bỏ" (mã bên dưới). Tôi đã gặp sự cố khi các yêu cầu liên tục bị hủy khi điều hướng đến một trang khác và kích hoạt phản hồiError.

angular.module("services.interceptor", arguments) 
    .config(function($httpProvider) { 
    $httpProvider.interceptors.push(function($q, $window) { 
     return { 
      responseError: function(rejection) { 
      if($window.event.type === "abort") { 
       // handle cancelled here 
      } else if(rejection.status < 1) { 
       alert("check your connection"); 
      } 
      return $q.reject(rejection); 
     } 
     }; 
    }); 
    }); 
}); 

(thêm: Thuộc tính trạng dường như đã thay đổi từ 0 đến -1 lỗi mạng, vì vậy tôi đã viết rejection.status < 1))

Các vấn đề liên quan