原生 Ajax 封裝 和 Axios 二次 封裝

来源:https://www.cnblogs.com/gaoguowen/archive/2019/05/22/10862914.html
-Advertisement-
Play Games

AJAX 非同步的JavaScript與XML技術( Asynchronous JavaScript and XML ) Ajax 不需要任何瀏覽器插件,能在不更新整個頁面的前提下維護數據,但需要用戶允許JavaScript在瀏覽器上執行。 相容性 封裝 XMLHttpRequest 對象 1 // ...


AJAX

非同步的JavaScript與XML技術( Asynchronous JavaScript and XML ) Ajax 不需要任何瀏覽器插件,能在不更新整個頁面的前提下維護數據,但需要用戶允許JavaScript在瀏覽器上執行。

相容性

 

封裝 XMLHttpRequest 對象

 1 // 創建 構造函數
 2 function Ajax(obj) {
 3     this.url = obj.url ||'';
 4     this.type = obj.type || 'get';
 5     this.data = obj.data ||{};
 6     this.success = obj.success || null;
 7     this.error = obj.error || null;
 8 }
 9 // 原型上創建方法支持 post 和 get
10 Ajax.prototype.send = function(){
11     var self = this;
12     var  toStr = Object.prototype.toString; 
13     if (self.data === null && typeof self.data !== 'object' && Array.isArray(obj)) return;
14     return (function(){
15             // 實例化 XML對象
16             var xhr = new XMLHttpRequest();
17             var data = '';
18             // 序列化參數
19             for (var k in self.data){
20                     data += k + '=' + self.data[k] + '&';
21             }
22             data = data.substr(0,data.length - 1);
23             // 接收回調函數             
24             xhr.onreadystatechange = function(){
25                 if (xhr.readyState === 4){
26                     if(xhr.status >= 200 && xhr.status < 300 || xhr.status == 304) {
27                         isFunction(self.success)  &&  self.success(xhr.responseText)
28                     }else{
29                         isFunction(self.error)  && self.error(xhr)
30                     }
31                 }
32             }
33             // 初始化請求
34             if(self.type.toLocaleLowerCase() === 'post'){
35                     xhr.open ('post',self.url,true)
36                     // 設置請求頭
37                     xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
38                     //發送請求
39                     xhr.send(data)
40                 } else {
41                     xhr.open('get', self.url + "?" + data,true)
42                     xhr.send(null)
43             }
44     }());
45 };
46 
47 function isFunction(obj){
48     return toStr.call(obj) === "[object Function]"
49 }
50 
51 var ajax = new Ajax({
52      type:'post',
53      url:"/login",
54      data:{ 
55          loginname:"admin",
56          password:"admin" 
57         },
58       success:function(e){
59             console.log(e)
60             }, 
61        error:function(err){
62               console.log(err)
63               },
64         }).send();

 

XMLHttpRequest Level 2 相比於 老版本的 XMLHttpRequest 新增以下內容:

可以設置 HTTP 請求超時時間
1 var xhr = XMLHttpRequest();
2  xhr.open('GET'.'url');
3  // 超時 2s
4  xhr.timeout = 2000;
5  // 超時處理
6  xhr.ontimeout = function(e) {
7      console.log(e)
8  }
9  xhr.send(null)
可以通過 FormData 發送表單數據
1  // 實例化 FormData
2  var formData = new FormData();
3   // 添加數據
4   formData.append(key,value);
5 
6   xhr.open('POST','url');
7   xhr.send(formData);
可以上傳文件
  • FormData 除了可以添加字元串數據,也可以添加 blob、file 類型的數據,因此可以用於上傳文件。
  • 在瀏覽器中,一般是通過文件上傳輸入框來獲取 file 對象,比如:
1 <input type="file" name='uploadFile' id="upload-file" />
1 document.getElementById('upload-file')
2         .addEventListener('change', function () {
3             
4             var formData = new FormData();
5             // 獲取數據
6               formData.append('uploadFile', this.files[0])
7                xhr.send(formData)
8       })
支持跨域請求
  • 瀏覽器預設是不允許跨域請求的,有時候又是必要的,在以前通常使用JSONP來解決(IE10 以下不支持)
  • 為了標準化跨域請求, W3C提出 跨域資源共用(CORS)前端無須修改代碼,只需 伺服器返回 Access-Control-Allow-Origin 響應頭,指定允許對應的域
  • CORS 預設不發送 cookie 如果需要發送,前端需要設置 withCredentials 屬性,同時伺服器需要 返回 Access-Control-Allow-Credentials: true,
     xhr.withCredentials = true;
可以獲取服務端二進位數據

1. 使用 overrideMimeType 方法覆寫伺服器指定的 MIME 類型,從而改變瀏覽器解析數據的方式

1 // 參數 MIME 類型
2 // 告訴瀏覽器,伺服器響應的內容是用戶自定義的字元集 
3 xhr.overrideMimeType('text/plain; charset=x-user-defined');
4 // 瀏覽器就會將伺服器返回的二進位數據當成文本處理,我們需要做進一步的轉換才能拿到真實的數據
5   // 獲取二進位數據的第 i 位的值
6   var byte = xhr.responseText.charCodeAt(i) & 0xff

 

  "& 0xff" 運算 參考 阮一峰的文章

2.xhr.responseType 用於設置伺服器返回的數據的類型,將返回類型設置為 blob 或者 arraybuffer,然後就可以從 xhr.response 屬性獲取到對應類型的伺服器返回數據。

1   xhr.responseType = 'arraybuffer'
2   xhr.onload = function () {
3   var arrayBuffer = xhr.response
4   // 接下來對 arrayBuffer 做進一步處理...
5   }

 

可以獲取數據傳輸進度信息 參考資料

使用 onload 監聽了一個數據傳輸完成的事件。

 
1 // 上傳進度監聽
2 xhr.upload.addEventListener('progress', onProgressHandler, false);
3 
4 // 傳輸成功完成
5 xhr.upload.addEventListener('load', onLoadHandler, false);
6 // 傳輸失敗信息
7 xhr.upload.addEventListener('error', onErrorHandler, false);

更多資料參考: 阮一峰的文章 MDN

 

AXIOS

  • 基於 Promise 的 Http 庫
  • 可以在客戶端 和 nodeJs中使用
  • 在客戶端創基 XMLHttpRequests
  • 在nodeJs 創建 HTTP 請求
  • 支持Promise
  • 可攔截轉化請求和響應數據
  • 取消請求
  • 自動轉化JSON數據
  • 支持客戶端 XSRF

 相容性

 

安裝

1 npm install axios

methods

Get

 1 const axios = require('axios')
 2 
 3 axios.get('url?id=xxx')
 4      .then(res => {
 5        console.log(res)
 6      })
 7      .catch(err =>{
 8        console.log(err)
 9      })
10 //or
11 axios.get('url',{
12   params:{
13     id:'xxxxx'
14   }
15     })
16    .then(res =>{
17      console.log(res)
18    })
19    .catch(err =>{
20        console.log(err)
21      })

同樣的傳參方法有 delete

post

axios.post('url',{name:'Owen'})
     .then(res =>{
       console.log(res)
     })
     .catch(err =>{
       console.log(err)
     })

同樣的傳參方法有 put patch

 

concurrent requests

1 axios.all([axios.get('url1'),axios.get('url2')])

API

axios(config)

  1 axios({
  2   method:'get', // default is get 
  3   url:'url', // request  url
  4   data:{ // 僅支持post,put和patch方法,數據作為請求主體發送 ( Only the post,put and patch methods are supported, and the data is sent as the request body )
  5   /* 瀏覽器僅支持傳遞 FormData, File, Blob (The browser only supports passing FormData, File and Blob)
  6      Node 僅支持傳遞 Stream, Buffer (The Node only supports passing Stream, Buffer)
  7   */
  8     name:'owen'
  9   },
 10   baseURL:'base/url', // 除非url是絕對路徑,否則將baseURL添加到url的前面 (Add baseURL to then front of the url unless the url is an absolute path)
 11   transformRequest: [function (data, headers) {
 12     // 可以修改發送的請求數據和請求頭,只支持put,post和patch,回調函數必須返回Buffer,ArrayBuffer,FormData或Stream數據
 13     // Can modify the sent request data and request header,only support put, post and patch.
 14     // Callback must return Buffer, ArrayBuffer, FormData or Stream data
 15     
 16     // Do whatever you want to transform the data
 17 
 18     return data;
 19   }],
 20   transformResponse: [function (data) {
 21      // 修改響應數據,再傳遞給 then或catch 方法 (Modify the response data and pass it to the then or catch method)
 22     // Do whatever you want to transform the data
 23 
 24     return data;
 25   }],
 26   headers: {'X-Requested-With': 'XMLHttpRequest'}, // 自定義請求頭 (Custom request header)
 27   params:{ // 添加到url尾部的參數,一般用於get 和 delete( Parameters addde to the end of the url,generally used for get and delete )
 28     id:'xxx'
 29   },
 30    paramsSerializer: function (params) { //序列化 [params] (https://www.npmjs.com/package/qs)
 31     return Qs.stringify(params, {arrayFormat: 'brackets'})
 32   },
 33   timeout:1000,// default is 0 , 設置請求超時時間,單位毫秒 ( Set request timeout in milliseconds )
 34   withCredentials: true, // default is false, 跨域時是否攜帶cookie( Whether to carry cookies when crossing domains )
 35   adapter: function (config) {
 36     /*攔截響應數據*/
 37       // At this point:
 38     //  - config has been merged with defaults
 39     //  - request transformers have already run
 40     //  - request interceptors have already run
 41     
 42     // Make the request using config provided
 43     // Upon response settle the Promise
 44       return new Promise(function(resolve, reject) {
 45   
 46     var response = {
 47       data: responseData,
 48       status: request.status,
 49       statusText: request.statusText,
 50       headers: responseHeaders,
 51       config: config,
 52       request: request
 53     };
 54 
 55     settle(resolve, reject, response);
 56 
 57     // From here:
 58     //  - response transformers will run
 59     //  - response interceptors will run
 60 
 61       /**
 62        * Resolve or reject a Promise based on response status.
 63        *
 64        * @param {Function} resolve A function that resolves the promise.
 65        * @param {Function} reject A function that rejects the promise.
 66        * @param {object} response The response.
 67        */
 68         function settle(resolve, reject, response) {
 69             var validateStatus = response.config.validateStatus;
 70             if (!validateStatus || validateStatus(response.status)) {
 71               resolve(response);
 72             } else {
 73               reject(createError(
 74                 'Request failed with status code ' + response.status,
 75                 response.config,
 76                 null,
 77                 response.request,
 78                 response
 79               ));
 80             }
 81           };
 82         /**
 83          * Create an Error with the specified message, config, error code, request and response.
 84          *
 85          * @param {string} message The error message.
 86          * @param {Object} config The config.
 87          * @param {string} [code] The error code (for example, 'ECONNABORTED').
 88          * @param {Object} [request] The request.
 89          * @param {Object} [response] The response.
 90          * @returns {Error} The created error.
 91          */
 92         function createError(message, config, code, request, response) {
 93           var error = new Error(message);
 94         return enhanceError(error, config, code, request, response);
 95           }
 96 
 97         /**
 98          * Update an Error with the specified config, error code, and response.
 99          *
100          * @param {Error} error The error to update.
101          * @param {Object} config The config.
102          * @param {string} [code] The error code (for example, 'ECONNABORTED').
103          * @param {Object} [request] The request.
104          * @param {Object} [response] The response.
105          * @returns {Error} The error.
106          */
107         function enhanceError(error, config, code, request, response) {
108             error.config = config;
109             if (code) {
110               error.code = code;
111             }
112 
113             error.request = request;
114             error.response = response;
115             error.isAxiosError = true;
116 
117             error.toJSON = function() {
118               return {
119                 // Standard
120                 message: this.message,
121                 name: this.name,
122                 // Microsoft
123                 description: this.description,
124                 number: this.number,
125                 // Mozilla
126                 fileName: this.fileName,
127                 lineNumber: this.lineNumber,
128                 columnNumber: this.columnNumber,
129                 stack: this.stack,
130                 // Axios
131                 config: this.config,
132                 code: this.code
133               };
134             };
135           return error;
136         }
137     });
138   },
139   auth:{ //  表示應使用HTTP Basic身份驗證,並提供憑據 ( indicates that HTTP Basic auth should be used, and supplies credentials. )
140     user:'xxx',
141     password:'***'
142   },
143   responseType: 'json',/* 伺服器響應的數據類型( The server response data type ) 
144                          支持 arraybuffer, blob, document, json, text, stream 
145                         */
146   responseEncoding:'utf8', // 用於解碼響應的編碼 (Encoding for decoding the response )
147   xsrfCookieName: 'XSRF-TOKEN', // default is XSRF-TOKEN , csrf令牌Cookie 名稱
148   xsrfHeaderName: 'X-XSRF-TOKEN', //default is X-XSRF-TOKEN, xsrf標記值的http標頭的名稱
149 onUploadProgress: function (progressEvent) { //上傳進度事件 (handling of progress events for uploads )
150     console.log(progressEvent)
151   },
152 onDownloadProgress: function (progressEvent) { // 下載進度事件 ( handling of progress events for downloads)
153    console.log(progressEvent)
154   },
155 maxContentLength: 2000, // 允許響應內容的最大位元組 (defines the max size of the http response content in bytes allowed)
156 validateStatus: function (status) { // 返回給定HTTP狀態範圍, 如果狀態在給定範圍內,響應數據傳給`then` ,否則傳給 `catch` ( Returns the given HTTP status range, if the status is within the give range, the respones data is passed to `then`, otherwise passed to `catch` ) 
157     return status >= 200 && status < 300; // default
158   },
159   maxRedirects: 5, // default is 5  // 定義Node 中最大重定向數  ( defines the maximunn number of redirects in Node )
160   socketPath: null, //  default is null 定義要在node.js中使用的 UNIX socket
161   httpAgent: new http.Agent({ keepAlive: true }), // node 中 http 和 https 的代理
162   httpsAgent: new https.Agent({ keepAlive: true }),// http://nodejs.cn/api/http.html
163   proxy: { // 代理配置
164     host: '127.0.0.1',
165     port: 9000,
166     auth: {
167       username: 'mikeymike',
168       password: 'rapunz3l'
169           }
170    },
171     cancelToken: new CancelToken(function (cancel) { // 取消請求的 token
172   })
173   })  
174   .then(res =>{
175        console.log(res)
176      })
177   .catch(err =>{
178        console.log(err)
179      })

全局配置

通過 axios.create 方法來替換全局配置

 

const instance = axios.create({
  baseURL: 'base/url'
});

 

通過axios.defaults 對象替換全局預設配置

1 instance.defaults.headers.common['Authorization'] = AUTH_TOKEN;
2 instance.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';

攔截器

 

攔截請求數據

 

1 axios.interceptors.request.use(function (config) {
2     return config;
3   }, function (error) {
4     return Promise.reject(error);
5   });

 

攔截響應數據

1 axios.interceptors.response.use(function (response) {
2     // Do something with response data
3     return response;
4   }, function (error) {
5     // Do something with response error
6     return Promise.reject(error);
7   });

刪除攔截器

 

1 const myInterceptor = axios.interceptors.request.use(function () {/*...*/});
2 axios.interceptors.request.eject(myInterceptor);

查閱更多信息

Axios 二次封裝

核心文件

  1 /**
  2   * @desc: axios封裝
  3   * @author: ggw 
  4   * @module: axios
  5   * @description: 配合使用 餓了麽的 Message和Loading
  6   * 
  7   */
  8  import axios from 'axios';
  9  import qs from 'qs';
 10  import {
 11      Message,
 12      Loading
 13  } from 'element-ui';
 14  
 15  import router from '../router'; 
 16  let loading;
 17  let headerNone = {
 18      'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
 19  };
 20  let headerTwo = {
 21      'Content-Type': 'application/json; charset=UTF-8'
 22  };
 23  let baseURL = window.location.origin ;
 24 
 25 
 26  /** 
 27   * @description: 定義初始化Loading
 28   * @method: startLoading 
 29   */
 30   const startLoading = () => {
 31      loading = Loading.service({
 32          target: '.content-box',
 33          background: 'rgba(220, 220, 220, 0.51)'
 34      });
 35  };
 36  
 37 
 38  let count = 0;
 39  /** 
 40   * @description: 顯示Loading 同時多個發送請求 只開啟一次Loading
 41   * @method: showLoading  && hideLoading
 42   */
 43   const showLoading = () => {
 44      if (count === 0) startLoading();
 45      count++;
 46  };
 47   const hideLoading = () => {
 48      if (count <= 0) return;
 49      count--;
 50      if (count === 0) {
 51          setTimeout(() => {
 52             loading.close();
 53          }, 300);
 54      }
 55  };
 56 
 57  export let filiter = r => {
 58 
 59      for (let item of Object.keys(r)) {
 60          if (r[item] === ' ' || r[item] === '') {
 61              delete r[item];
 62          }
 63      }
 64  };
 65  /** 
 66   * @description: 出口
 67   * @exports api
 68   * @param:options 必須是對象
 69   * options 對象為 axios對應參數
 70   */
 71  export default (options) => {
 72      /** 
 73       * @description: 用來初始化承諾的回調。
 74       * 這個回調被傳遞了兩個參數:
 75       * 一個解析回調用一個值或另一個承諾的結果來解析承諾,
 76       * 以及一個拒絕回調,用來拒絕承諾的原因或錯誤。
 77       * @constructor: Promise
 78       */
 79      return new Promise((resolve, reject) => {
 80          const instance = axios.create({
 81              withCredentials: true,
 82              headers: headerNone,
 83              baseURL
 84          });
 85          // 請求攔截器
 86          instance.interceptors.request.use(config => {
 87               let {load = true} = config.data || config.params || {} ;
 88              if (load) showLoading();
 89              //  過濾無值參數
 90              if (config.params) {
 91                 delete config.params.load;
 92                  filiter(config.params);
 93                 } else if (config.data) {
 94                  filiter(config.data);
 95                 delete config.data.load;
 96                 }
 97              if (
 98                  config.method.toLocaleLowerCase() === 'post' ||
 99                  config.method.toLocaleLowerCase() === 'put'
100              ) {
101                  // json 格式傳遞
102                  if (config.json) {
103                      config.headers = headerTwo;
104                  } else {
105                      config.data = qs.stringify(config.data);
106                      config.data = config.data + '&t=' + Date.now();
107                  }
108              }
109              return config;
110          }, error => {
111               hideLoading();
112              return Promise.reject(error);
113          });
114          // 響應攔截器
115          instance.interceptors.response.use(response => {
116             setTimeout(hideLoading,0);
117              let data;
118              // IE9時response.data是undefined,因此需要使用response.request.responseText(Stringify後的字元串)
119              if (!response.data ) {
120                  data = response.request.responseText;
121              } else {
122                  data = response.data;
123              }
124 
125              switch (data.code) { // 介面定義欄位
126                  case '001':
127                      Message({
128                          showClose: true,
129                          message: data.msg |

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 簡單記錄一下 前段時間接到客戶需求:動態改變下拉列表框ComboBox輸入框的背景顏色。 剛開始想的很簡單在用戶選擇列表項的時候,判斷一下列表框的value值添加相應的背景顏色就OK了,然而在實際操作的時候發現,怎麼操作都沒有效果,後來檢查了一下html結構才知道原來操作的不是顯示在頁面上的元素,害 ...
  • 一、在運行rn app應用時,react-native run:ios 報錯出現 解決辦法: 1、react-native run-ios --simulator="iPhone 6",運行時指定啟動版本 2 、Open file: 打開:node_modules/react-native/loca ...
  • 有關JSON的個人理解: JSON其實就是一個獨立於任何編程語言的獨立的輕量的數據交換的東西,方便於人的閱讀和機器的解析。裡面的內容還是鍵值對的形式存在的,可以對其進行增刪改查的,但是當從資料庫中調用數據的時候,需要對其進行數據的轉換。 一、JSON含義: JSON的全稱是”JavaScript O ...
  • 一、ul無序列表 1、無序列表定義 無序列表是一個項目的列表,此列項目使用粗體圓點(典型的小黑圓圈)進行標記。 無序列表始於 <ul>標簽。每個列表項始於 <li>。 ul標簽結構: <ul> <li>清心</li> <li>海牙</li> <li>玄武</li> </ul> 2、無序列表項目符號  ...
  • 一.== vs ==在做判斷時,如果對比雙方的類型不一樣的話,就會進行類型轉換 假如我們需要對比 x 和 y 是否相同,就會進行如下判斷流程: 首先會判斷兩者類型是否相同。相同的話就是比大小了 類型不相同的話,那麼就會進行類型轉換 判斷兩個類型是否為string 和number,是的話就將strin ...
  • 經過前面幾次的學習,已經可以做下小功能,今天要實現的事用戶登錄路由。 一、users_model.js 功能:定義用戶對象模型 二、users_controller.js 功能:為Express伺服器實現用戶登錄路由 三、login.html 四、routes.js 功能:為Express伺服器實現 ...
  • 首部 通用首部:有些首部提供了與報文相關的最基本的信息,它們被稱為通用首部。 請求首部:請求首部是只在請求報文中有意義的首部。 響應首部 實體首部: 用來描述HTTP報文的負荷,由於請求和響應報文中都可能包含實 體部分,所以在這兩種類型的報文中都可能出現這些首部。實體首部提供了有關實體及其內容的大量 ...
  • 在昨天寫的隨筆中: layui的tree和form同時引用出現衝突的粗略解決辦法 https://www.cnblogs.com/xwma/p/10900975.html 提出有衝突,今天在開發中發現並不是這樣的,他們並沒有衝突! 依舊是昨天的代碼,如下: 1 <textarea class="la ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...