場景描述:
ajax設置timeout在本機測試有效,但是在生產環境等外網環境無效的問題
1.ajax的timeout屬性設置 前端請求超時事件【網絡連接不穩定時候,就無效了】
var data = JSON字符串; $.ajax({ type: "POST", url: url, dataType: 'json', timeout: 3000,//3s鍾超時
data: data, xhrFields: { withCredentials: true }, success: function (json) { alert("保存成功") }, error: function (err, textStatus, errorThrown) { alert("保存失敗") } });
屬性說明:
timeout: //單位是毫秒值 timeout: 0 //代表永不超時
其他說明:
當然,ajax里面設置的是前端超時事件,后端服務 的接口 也有超時時間。
聲明: timeout屬性設置的超時時間,肯定是有效果的。
但是 在生產環境等時候,因為網絡跳動不穩定,導致 前后端連接中斷了,即使這里的超時時間設置再大 或者設置永不超時,也會進入error,即會發生超時情況。這種時候,就需要 在前端使用輪詢去解決這種問題了。
2.spring boot為例,設置接口超時時間的兩種方式
1> 在配置文件application.properties中加了spring.mvc.async.request-timeout=20000,意思是設置超時時間為20000ms即20s,
2>還有一種就是在config配置類中加入 public class WebMvcConfig extends WebMvcConfigurerAdapter { @Override public void configureAsyncSupport(final AsyncSupportConfigurer configurer) { configurer.setDefaultTimeout(20000); configurer.registerCallableInterceptors(timeoutInterceptor()); } @Bean public TimeoutCallableProcessingInterceptor timeoutInterceptor() { return new TimeoutCallableProcessingInterceptor(); } }
3.前端輪詢方案 ,查詢后端的保存狀態,直到查詢到后端的保存狀態為成功,才做相應的用戶響應操作 【解決ajax設置timeout避免不了的網絡不穩定的問題】
輪詢方案簡介:
這里就要對 1中的 ajax進行改造了 。
這里使用 js的 setInterval()發起輪詢 clearInterval()停止輪詢
setInterval(code,millisec)
參數 描述
code 必需。要調用的函數或要執行的代碼串。
millisec 必須。周期性執行或調用 code 之間的時間間隔,以毫秒計。
setInterval() 方法可按照指定的周期(以毫秒計)來調用函數或計算表達式。
setInterval() 方法會不停地調用函數,直到 clearInterval() 被調用或窗口被關閉。由 setInterval() 返回的 ID 值可用作 clearInterval() 方法的參數。
輪詢方案代碼:
var data = JSON字符串; var myFlag = new Date().getTime(); //作為本次保存的 唯一標識
data.myFlag = myFlag; //作為后端入參傳給后台
$.ajax({ type: "POST", url: url, dataType: 'json', timeout: 0,//永不超時
data: data, xhrFields: { withCredentials: true }, success: function (json) { alert("處理成功的邏輯 依舊寫在這里"); }, error: function (err, textStatus, errorThrown) { //此處要判斷 error時候,是不是因為超時導致的,如果是超時導致的error,那就做輪詢
if (textStatus == 408 || textStatus == 'timeout') { //輪詢查詢批量保存狀態
window.myFlag2222 = setInterval(function (){ this.batchSaveTimer(myFlag); },6000); }else { loading.hide(); $('.J_button_submit').prop('disabled', false); tips.show("保存失敗"); } } }); batchSaveTimer: function (flag) { $.ajax({ type:'get', url: url + "/" + flag, dataType:'json', cache:true, xhrFields: { withCredentials: true }, success:function(result) { if (result.code && result.code == 'success' ) { //當后端保存狀態為1 代表保存成功
if (result.data == '1') { //這里就 停止輪詢 入參一定是 發起輪詢的setInterval()方法的返回值
clearInterval(window.myFlag2222); alert("這里同樣寫一份 處理成功的邏輯"); //當后端保存狀態為-1 代表保存失敗
} else if (result.data == '-1') { //這里視業務而定,是否停止輪詢
clearInterval(window.myFlag2222); alert("這里寫一份 處理失敗的邏輯"); } } }, error:function() { alert("服務器異常") } }); },
附錄說明:
當然,后端處理也很簡單,在redis記錄一個 status. myFlag作為key status作為value 開始保存,把status設置為0 開始處理 status設置為1 處理成功 status設置為-1 處理失敗