將HTML導出生成word文檔

来源:http://www.cnblogs.com/aaron-pan/archive/2017/07/07/7132059.html
-Advertisement-
Play Games

前言: 項目開發中遇到了需要將HTML頁面的內容導出為一個word文檔,所以有了這邊隨筆。 當然,項目開發又時間有點緊迫,第一時間想到的是用插件,所以百度了下。下麵就介紹兩個導出word文檔的方法。 法一:通過jquery.wordexport.js導出word 備註:相容IE9以上 大概瀏覽了下j ...


 

前言:

項目開發中遇到了需要將HTML頁面的內容導出為一個word文檔,所以有了這邊隨筆。

當然,項目開發又時間有點緊迫,第一時間想到的是用插件,所以百度了下。下麵就介紹兩個導出word文檔的方法。

法一:通過jquery.wordexport.js導出word

備註:相容IE9以上

大概瀏覽了下jquery.wordexport.js插件的代碼,瞭解到了通過該插件可以導出文本和圖片,而圖片首先通過canvas的形式

繪製,文本則需要再依賴FileSaver.js插件,FileSaver.js插件則主要通過H5的文件操作新特性new Blob()和new FileReader()

來實現文本的導出。

插件源碼:

FileSaver.js

  1 /* FileSaver.js
  2  * A saveAs() FileSaver implementation.
  3  * 1.3.2
  4  * 2016-06-16 18:25:19
  5  *
  6  * By Eli Grey, http://eligrey.com
  7  * License: MIT
  8  *   See https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md
  9  */
 10 
 11 /*global self */
 12 /*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */
 13 
 14 /*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */
 15 
 16 var saveAs = saveAs || (function(view) {
 17         "use strict";
 18         // IE <10 is explicitly unsupported
 19         if (typeof view === "undefined" || typeof navigator !== "undefined" && /MSIE [1-9]\./.test(navigator.userAgent)) {
 20             return;
 21         }
 22         var
 23             doc = view.document
 24         // only get URL when necessary in case Blob.js hasn't overridden it yet
 25             , get_URL = function() {
 26                 return view.URL || view.webkitURL || view;
 27             }
 28             , save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a")
 29             , can_use_save_link = "download" in save_link
 30             , click = function(node) {
 31                 var event = new MouseEvent("click");
 32                 node.dispatchEvent(event);
 33             }
 34             , is_safari = /constructor/i.test(view.HTMLElement)
 35             , is_chrome_ios =/CriOS\/[\d]+/.test(navigator.userAgent)
 36             , throw_outside = function(ex) {
 37                 (view.setImmediate || view.setTimeout)(function() {
 38                     throw ex;
 39                 }, 0);
 40             }
 41             , force_saveable_type = "application/octet-stream"
 42         // the Blob API is fundamentally broken as there is no "downloadfinished" event to subscribe to
 43             , arbitrary_revoke_timeout = 1000 * 40 // in ms
 44             , revoke = function(file) {
 45                 var revoker = function() {
 46                     if (typeof file === "string") { // file is an object URL
 47                         get_URL().revokeObjectURL(file);
 48                     } else { // file is a File
 49                         file.remove();
 50                     }
 51                 };
 52                 setTimeout(revoker, arbitrary_revoke_timeout);
 53             }
 54             , dispatch = function(filesaver, event_types, event) {
 55                 event_types = [].concat(event_types);
 56                 var i = event_types.length;
 57                 while (i--) {
 58                     var listener = filesaver["on" + event_types[i]];
 59                     if (typeof listener === "function") {
 60                         try {
 61                             listener.call(filesaver, event || filesaver);
 62                         } catch (ex) {
 63                             throw_outside(ex);
 64                         }
 65                     }
 66                 }
 67             }
 68             , auto_bom = function(blob) {
 69                 // prepend BOM for UTF-8 XML and text/* types (including HTML)
 70                 // note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF
 71                 if (/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) {
 72                     return new Blob([String.fromCharCode(0xFEFF), blob], {type: blob.type});
 73                 }
 74                 return blob;
 75             }
 76             , FileSaver = function(blob, name, no_auto_bom) {
 77                 if (!no_auto_bom) {
 78                     blob = auto_bom(blob);
 79                 }
 80                 // First try a.download, then web filesystem, then object URLs
 81                 var
 82                     filesaver = this
 83                     , type = blob.type
 84                     , force = type === force_saveable_type
 85                     , object_url
 86                     , dispatch_all = function() {
 87                         dispatch(filesaver, "writestart progress write writeend".split(" "));
 88                     }
 89                 // on any filesys errors revert to saving with object URLs
 90                     , fs_error = function() {
 91                         if ((is_chrome_ios || (force && is_safari)) && view.FileReader) {
 92                             // Safari doesn't allow downloading of blob urls
 93                             var reader = new FileReader();
 94                             reader.onloadend = function() {
 95                                 var url = is_chrome_ios ? reader.result : reader.result.replace(/^data:[^;]*;/, 'data:attachment/file;');
 96                                 var popup = view.open(url, '_blank');
 97                                 if(!popup) view.location.href = url;
 98                                 url=undefined; // release reference before dispatching
 99                                 filesaver.readyState = filesaver.DONE;
100                                 dispatch_all();
101                             };
102                             reader.readAsDataURL(blob);
103                             filesaver.readyState = filesaver.INIT;
104                             return;
105                         }
106                         // don't create more object URLs than needed
107                         if (!object_url) {
108                             object_url = get_URL().createObjectURL(blob);
109                         }
110                         if (force) {
111                             view.location.href = object_url;
112                         } else {
113                             var opened = view.open(object_url, "_blank");
114                             if (!opened) {
115                                 // Apple does not allow window.open, see https://developer.apple.com/library/safari/documentation/Tools/Conceptual/SafariExtensionGuide/WorkingwithWindowsandTabs/WorkingwithWindowsandTabs.html
116                                 view.location.href = object_url;
117                             }
118                         }
119                         filesaver.readyState = filesaver.DONE;
120                         dispatch_all();
121                         revoke(object_url);
122                     }
123                     ;
124                 filesaver.readyState = filesaver.INIT;
125 
126                 if (can_use_save_link) {
127                     object_url = get_URL().createObjectURL(blob);
128                     setTimeout(function() {
129                         save_link.href = object_url;
130                         save_link.download = name;
131                         click(save_link);
132                         dispatch_all();
133                         revoke(object_url);
134                         filesaver.readyState = filesaver.DONE;
135                     });
136                     return;
137                 }
138 
139                 fs_error();
140             }
141             , FS_proto = FileSaver.prototype
142             , saveAs = function(blob, name, no_auto_bom) {
143                 return new FileSaver(blob, name || blob.name || "download", no_auto_bom);
144             }
145             ;
146         // IE 10+ (native saveAs)
147         if (typeof navigator !== "undefined" && navigator.msSaveOrOpenBlob) {
148             return function(blob, name, no_auto_bom) {
149                 name = name || blob.name || "download";
150 
151                 if (!no_auto_bom) {
152                     blob = auto_bom(blob);
153                 }
154                 return navigator.msSaveOrOpenBlob(blob, name);
155             };
156         }
157 
158         FS_proto.abort = function(){};
159         FS_proto.readyState = FS_proto.INIT = 0;
160         FS_proto.WRITING = 1;
161         FS_proto.DONE = 2;
162 
163         FS_proto.error =
164             FS_proto.onwritestart =
165                 FS_proto.onprogress =
166                     FS_proto.onwrite =
167                         FS_proto.onabort =
168                             FS_proto.onerror =
169                                 FS_proto.onwriteend =
170                                     null;
171 
172         return saveAs;
173     }(
174         typeof self !== "undefined" && self
175         || typeof window !== "undefined" && window
176         || this.content
177     ));
178 // `self` is undefined in Firefox for Android content script context
179 // while `this` is nsIContentFrameMessageManager
180 // with an attribute `content` that corresponds to the window
181 
182 if (typeof module !== "undefined" && module.exports) {
183     module.exports.saveAs = saveAs;
184 } else if ((typeof define !== "undefined" && define !== null) && (define.amd !== null)) {
185     define([], function() {
186         return saveAs;
187     });
188 }
View Code

jquery.wordexport.js

 1 if (typeof jQuery !== "undefined" && typeof saveAs !== "undefined") {
 2     (function($) {
 3         $.fn.wordExport = function(fileName) {
 4             fileName = typeof fileName !== 'undefined' ? fileName : "jQuery-Word-Export";
 5             var static = {
 6                 mhtml: {
 7                     top: "Mime-Version: 1.0\nContent-Base: " + location.href + "\nContent-Type: Multipart/related; boundary=\"NEXT.ITEM-BOUNDARY\";type=\"text/html\"\n\n--NEXT.ITEM-BOUNDARY\nContent-Type: text/html; charset=\"utf-8\"\nContent-Location: " + location.href + "\n\n<!DOCTYPE html>\n<html>\n_html_</html>",
 8                     head: "<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n<style>\n_styles_\n</style>\n</head>\n",
 9                     body: "<body>_body_</body>"
10                 }
11             };
12             var options = {
13                 maxWidth: 624
14             };
15             // Clone selected element before manipulating it
16             var markup = $(this).clone();
17 
18             // Remove hidden elements from the output
19             markup.each(function() {
20                 var self = $(this);
21                 if (self.is(':hidden'))
22                     self.remove();
23             });
24 
25             // Embed all images using Data URLs
26             var images = Array();
27             var img = markup.find('img');
28             for (var i = 0; i < img.length; i++) {
29                 // Calculate dimensions of output image
30                 var w = Math.min(img[i].width, options.maxWidth);
31                 var h = img[i].height * (w / img[i].width);
32                 // Create canvas for converting image to data URL
33                 var canvas = document.createElement("CANVAS");
34                 canvas.width = w;
35                 canvas.height = h;
36                 // Draw image to canvas
37                 var context = canvas.getContext('2d');
38                 context.drawImage(img[i], 0, 0, w, h);
39                 // Get data URL encoding of image
40                 var uri = canvas.toDataURL("image/png/jpg");
41                 $(img[i]).attr("src", img[i].src);
42                 img[i].width = w;
43                 img[i].height = h;
44                 // Save encoded image to array
45                 images[i] = {
46                     type: uri.substring(uri.indexOf(":") + 1, uri.indexOf(";")),
47                     encoding: uri.substring(uri.indexOf(";") + 1, uri.indexOf(",")),
48                     location: $(img[i]).attr("src"),
49                     data: uri.substring(uri.indexOf(",") + 1)
50                 };
51             }
52 
53             // Prepare bottom of mhtml file with image data
54             var mhtmlBottom = "\n";
55             for (var i = 0; i < images.length; i++) {
56                 mhtmlBottom += "--NEXT.ITEM-BOUNDARY\n";
57                 mhtmlBottom += "Content-Location: " + images[i].location + "\n";
58                 mhtmlBottom += "Content-Type: " + images[i].type + "\n";
59                 mhtmlBottom += "Content-Transfer-Encoding: " + images[i].encoding + "\n\n";
60                 mhtmlBottom += images[i].data + "\n\n";
61             }
62             mhtmlBottom += "--NEXT.ITEM-BOUNDARY--";
63 
64             //TODO: load css from included stylesheet
65 
66             //var styles=' /* Font Definitions */@font-face{font-family:宋體;panose-1:2 1 6 0 3 1 1 1 1 1;mso-font-alt:SimSun;mso-font-charset:134;mso-generic-font-family:auto;mso-font-pitch:variable;mso-font-signature:3 680460288 22 0 262145 0;}  @font-face{font-family:"Cambria Math";panose-1:2 4 5 3 5 4 6 3 2 4;mso-font-charset:1;mso-generic-font-family:roman;mso-font-format:other;mso-font-pitch:variable;mso-font-signature:0 0 0 0 0 0;}  @font-face{font-family:"\@宋體";panose-1:2 1 6 0 3 1 1 1 1 1;mso-font-charset:134;mso-generic-font-family:auto;mso-font-pitch:variable;mso-font-signature:3 680460288 22 0 262145 0;}/* Style Definitions */p.MsoNormal, li.MsoNormal, div.MsoNormal{mso-style-unhide:no;mso-style-qformat:yes;mso-style-parent:"";margin:0cm;margin-bottom:.0001pt;mso-pagination:widow-orphan;font-size:14.0pt;font-family:宋體;mso-bidi-font-family:宋體;}p.MsoHeader, li.MsoHeader, div.MsoHeader{mso-style-noshow:yes;mso-style-priority:99;mso-style-link:"頁眉 Char";margin:0cm;margin-bottom:.0001pt;text-align:center;mso-pagination:widow-orphan;layout-grid-mode:char;font-size:9.0pt;font-family:宋體;mso-bidi-font-family:宋體;}p.MsoFooter, li.MsoFooter, div.MsoFooter{mso-style-noshow:yes;mso-style-priority:99;mso-style-link:"頁腳 Char";margin:0cm;margin-bottom:.0001pt;mso-pagination:widow-orphan;layout-grid-mode:char;font-size:9.0pt;font-family:宋體;mso-bidi-font-family:宋體;}p.MsoAcetate, li.MsoAcetate, div.MsoAcetate{mso-style-noshow:yes;mso-style-priority:99;mso-style-link:"批註框文本 Char";margin:0cm;margin-bottom:.0001pt;mso-pagination:widow-orphan;font-size:9.0pt;font-family:宋體;mso-bidi-font-family:宋體;}span.Char{mso-style-name:"頁眉 Char";mso-style-noshow:yes;mso-style-priority:99;mso-style-unhide:no;mso-style-locked:yes;mso-style-link:頁眉;font-family:宋體;mso-ascii-font-family:宋體;mso-fareast-font-family:宋體;mso-hansi-font-family:宋體;}span.Char0{mso-style-name:"頁腳 Char";mso-style-noshow:yes;mso-style-priority:99;mso-style-unhide:no;mso-style-locked:yes;mso-style-link:頁腳;font-family:宋體;mso-ascii-font-family:宋體;mso-fareast-font-family:宋體;mso-hansi-font-family:宋體;}span.Char1{mso-style-name:"批註框文本 Char";mso-style-noshow:yes;mso-style-priority:99;mso-style-unhide:no;mso-style-locked:yes;mso-style-link:批註框文本;font-family:宋體;mso-ascii-font-family:宋體;mso-fareast-font-family:宋體;mso-hansi-font-family:宋體;}p.msochpdefault, li.msochpdefault, div.msochpdefault{mso-style-name:msochpdefault;mso-style-unhide:no;mso-margin-top-alt:auto;margin-right:0cm;mso-margin-bottom-alt:auto;margin-left:0cm;mso-pagination:widow-orphan;font-size:10.0pt;font-family:宋體;mso-bidi-font-family:宋體;}span.msonormal0{mso-style-name:msonormal;mso-style-unhide:no;}.MsoChpDefault{mso-style-type:export-only;mso-default-props:yes;font-size:10.0pt;mso-ansi-font-size:10.0pt;mso-bidi-font-size:10.0pt;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:"Times New Roman";mso-font-kerning:0pt;}/* Page Definitions */  @page WordSection1{size:595.3pt 841.9pt;margin:72.0pt 90.0pt 72.0pt 90.0pt;mso-header-margin:42.55pt;mso-footer-margin:49.6pt;mso-paper-source:0;}div.WordSection1{page:WordSection1;}';
67 
68             var styles="";
69 
70             // Aggregate parts of the file together
71             var fileContent = static.mhtml.top.replace("_html_", static.mhtml.head.replace("_styles_", styles) + static.mhtml.body.replace("_body_", markup.html())) + mhtmlBottom;
72 
73             // Create a Blob with the file contents
74             var blob = new Blob([fileContent], {
75                 type: "application/msword;charset=utf-8"
76             });
77             saveAs(blob, fileName + ".doc");
78         };
79     })(jQuery);
80 } else {
81     if (typeof jQuery === "undefined") {
82         console.error("jQuery Word Export: missing dependency (jQuery)");
83     }
84     if (typeof saveAs === "undefined") {
85         console.error("jQuery Word Export: missing dependency (FileSaver.js)");
86     }
87 }
View Code

插件調用:

 1 <!DOCTYPE html>
 2 <html>
 3 <head lang="en">
 4     <meta charset="UTF-8">
 5     <title>生成word文檔</title>
 6 </head>
 7 <body lang=ZH-CN style='tab-interval:21.0pt'>
 8 <div class="word">
 9     <p align="center" style="font-size:20pt;font-weight:bold;">JS導出Word文檔</p>
10 </div>
11 <input type="button" value="導出word">
12 <script src="https://cdn.bootcss.com/jquery/2.2.4/jquery.js"></script>
13 <script type="text/javascript" src="js/FileSaver.js"></script>
14 <script type="text/javascript" src="js/jquery.wordexport.js"></script>
15 <script>
16     $(function(){
17         $("input[type='button']").click(function(event) {
18             $(".word").wordExport('生成word文檔');
19         });
20     })
21 </script>
22 </body>
23 </html>

直接調用wordExport()介面就可以導出word文檔,傳的參數為導出的word文件名。

補充:

通過我們常規寫的外聯樣式設置樣式是無效的,通過個人的實踐發現需要寫內聯樣式才能生效,而單位也需要按照word的配置

單位pt設置。

而jquery.wordexport.js插件是要配置了個style樣式讓我們補充樣式設置的:

但是個人實踐了下,設置的樣式卻無法生效,只能通過內聯設置才生效。

截圖:

法二:通過百度js模板引擎生成word文檔

主要是通過js模板設置對應的標簽,然後XDoc.to(baidu.template())導出word,而通過百度js模板引擎的好處是也可以導出PDF文件。

完整demo:

 1 <!DOCTYPE html>
 2 <html>
 3 <head>
 4     <meta charset="UTF-8">
 5     <script type="text/javascript" src="http://www.xdocin.com/xdoc.js"></script>
 6     <script type="text/javascript" src="http://www.xdocin.com/baiduTemplate.js"></script>
 7     <style>
 8         .head{
 9             font-size: 29px;
10             display: block;
11         }
12         .content{
13             display: block;
14         }
15     </style>
16 </head>
17 <body>
18 <input type="button" onclick="gen('pdf')" value="生成PDF"/>
19 <input type="button" onclick="gen('docx')" value="生成Word"/>
20 <br/>
21 <script id="tmpl" type="text/html">
22     <xdoc version="A.3.0">
23         <body>
24         <para heading="1" lineSpacing="28">
25             <text class="head" valign="center" fontName="標宋" fontSize="29"><%=title%></text>
26         </para>
27         <para>
28             <img  src="<%=img%>" sizeType="autosize"/>
29         </para>
30         <para lineSpacing="9"
              
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1.使用 代替 ==JavaScript 使用2種不同的等值運算符: |!== 和 ==|!=,在比較操作中使用前者是最佳實踐。“如果兩邊的操作數具有相同的類型和值, 返回true,!==返回false。”——JavaScript:語言精粹然而,當使用==和!=時,你可能會遇到類型不同的情況,這種情 ...
  • 前端新手自己寫的,練習一下基本功,也是在博客園留下的第一次記錄 html部分 css部分 js部分 ...
  • JavaScript是一種解釋型語言而不是編譯型語言,它往往被認為是一種腳本語言,而不被看作是一種真正的編程語言。也就是說,腳本語言比較簡單,它們是非程式員所使用的編程語言。 如果一個程式員對JavaScript沒有扎實的理解,那麼當他要用JavaScript執行較複雜的任務時,就會發現整個過程困難 ...
  • 一個經典的問題: 0.1+0.2==0.3 答案是:false 因為:0.1+0.2=0.30000000000000004 第一次看到這個結果就是無比驚訝,下巴碰到地上,得深入瞭解下問題出在哪裡,該怎麼去調整。 產生問題的原因 在JS中數值類型就只有number類型,沒有int,float,dou ...
  • 好幾天沒有進行每日一練了,除了工作原因之外,還有因為近期看到同事發的各種剛入職場的學弟學妹們的簡歷,被上面寫的各種掌握的技能所刺激了。雖然可能不是那麼盡實,但著實的push自己一把,決定先把canvas啃下來。 我試水了畫了一個時鐘,和MDN的例子略有一點不同。I work it by myself ...
  • 最近在百度搜索的時候,當你輸入一個字或者詞的時候,他會給你們彈出一個下拉框出來,裡面是和你相關的搜索提示 比如 我輸入楊字,他會給我提示以下搜索提示 我嘗試著用JavaScript做了一個類似的練習,以下是我用VS2013寫的代碼,有不對的地方,請不吝賜教。 效果展示: 關於這個練習我有以下幾點思索 ...
  • WebSocket是HTML5開始提供的一種單個TCP連接上進行全雙工通訊的協議。在WebSocket API中,瀏覽器和伺服器只需要做一個握手的動作,然後,瀏覽器和伺服器之間就形成了一條快速通道。兩者之間就直接可以數據相互傳送。瀏覽器通過JavaScript向伺服器發出建立WebSocket連接的 ...
  • 重新看js閉包的時候看到了《大部分人都會做錯的經典JS閉包面試題》,自己理解並記錄了下想法。很多部分博主已經講得很詳細了,只是後面的解釋部分文字有點繞。 原帖地址:http://web.jobbole.com/84328/ 先貼代碼 問:每一個輸出分別是什麼? 答案: 來逐步拆解: ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...