果我們測試一個版本時遇到Bug,然后等開發改了以后及時驗證,開發可能會好心提醒一句,你先清一下瀏覽器緩存再測,是不是經常碰到這種情況?所以我們在測試中要經常和緩存打交道,既然是老朋友了,那我們干脆來好好認識一下它。
緩存基本上是對網頁上經常訪問的資源的存儲和重用。由于存儲是在快速訪問的地方完成的,因此導航速度更快,這也提高了網站和應用程序的性能。這就是為什么 HTTP 緩存對于想要優化用戶體驗并因此增加收入的企業來說是必不可少的工具。
每一毫秒都很重要
如果你被問到一個網站最讓你煩惱的是什么,你可能會回答說這是一個網站加載速度很慢。而且有調查顯示:70%的消費者表示,網頁加載的速度會直接影響他們在線購買的意愿。網頁的緩慢加載和呈現會影響用戶體驗,從而導致失去客戶參與和銷售的機會。
由于我們生活在即時性的時代,因此在虛擬世界中逃脫的任何事物都是失敗的代名詞。百度和其他搜索引擎在對搜索進行排名時不會推薦緩慢的網站,想象一下用戶在等待查看和瀏覽網站時的體驗和時間消耗。
在訪問量大的時候,使網站更快的有效方法是使用緩存。你應該聽說過緩存,至于它是什么,以及如何工作的,這就是接下來要談的內容。
什么是 HTTP 緩存?
為了更好地理解什么是HTTP緩存,首先你得知道HTTP是什么。簡而言之HTTP是一種基于文本的應用層傳輸協議,我們一般稱之為“超文本傳輸協議”,基于該協議可以傳輸如圖像、圖形、URL、 HTML 文本和腳本之類,那么這些的存儲和重用,那這樣留下備份就被稱為緩存,從而防止每次訪問頁面時都下載它們。緩存的主要目的是通過重用以前的響應消息來滿足當前的請求來提高通信性能。
HTTP 緩存是如何工作的?
緩存的工作方式如下:
緩存的類型
緩存的類型是根據內容的存儲位置定義的。
緩存頭
在緩存頭中,給出了用于定義緩存特征的指令。例如:
緩存控制
在緩存頭中,可以為緩存提供以下標準指令:
內容被視為私有內容,因為只有一個用戶有權訪問。在這種情況下,私有內容可以由客戶端的瀏覽器存儲,但不能由中間緩存存儲。
內容被視為公開內容,因為多個用戶可以訪問。內容可以由瀏覽器存儲,也可以存儲在客戶端和服務器之間的其他緩存中。
定義在不在源服務器上重新驗證的情況下可以緩存內容的最長時間。時間以秒為單位定義,最大值為一年(31,536,000 秒)。
無法緩存內容,因此請求始終發送到源服務器。傳輸機密數據時會標明此格式。
必須在每個新請求中重新驗證緩存的內容,這會使內容立即過時。在這種情況下,緩存會在釋放存儲的副本之前將請求發送到源服務器進行驗證。
指示可以緩存內容的時間量,因此與 max-age 非常相似,但不同之處在于此選項僅適用于中間緩存,而不適用于瀏覽器。
Expires 標頭定義內容何時過期。在指定的時間之后,緩存的內容將被視為過時,因此請求將有權訪問源服務器上的最新內容。
Etag(實體標簽)標頭用于驗證瀏覽器的緩存資源是否與源服務器上的緩存資源相同。也就是說,它驗證客戶端是否正在接收緩存內容的最新版本。此標頭用作與網站上每個資源關聯的唯一標識符。為了進行標識,網頁服務器使用 Etag 值,該值在每次更改資源時都會修改。ETag 值是上次更新資源的日期和時間。
Last-Modified 標頭顯示瀏覽器上次修改資源的時間,以及它是否應使用緩存的副本或下載最新版本。例如,當用戶訪問您的網站時,瀏覽器會存儲頁面的資源,因此當他們下次訪問該網站時,服務器會檢查文件自上次訪問以來是否已更改。如果沒有修改,服務器會向瀏覽器發送“304 not modified”響應,并使用緩存的副本。
Vary 標頭可以存儲相同內容的不同版本,因此它用于請求緩存以在決定請求哪些內容之前檢查其他標頭。例如,當與 Accept-Encoding 標頭一起使用時,該設置允許區分壓縮和未壓縮的內容,或者當與User-Agent 標頭一起使用時,它會區分移動或桌面網站的版本。
緩存的好處
測試人員在什么場景下要留意緩存
1.及時驗證測試
這是最常見的一類需要注意緩存的情況,就是如果遇到一些小bug,需要開發立即改好后驗證,那就可以等開發改完,測試這邊需要把驗證用到的瀏覽器緩存清除一次,因為很可能頁面還用的之前的緩存數據;
2. 頁面加載性能測試
緩存可以用于加速頁面加載時間。測試人員需要驗證頁面加載性能,并確保緩存策略不會導致頁面內容過時或不一致;
3. 數據一致性測試
當應用程序使用緩存來存儲數據時,測試人員需要測試緩存對數據一致性的影響。驗證數據在緩存和數據庫之間的同步性,以及在數據更新時緩存的更新機制,這點也是很重要的;
4. 用戶認證和授權測試
緩存可能包含用戶的認證和授權信息。測試人員需要驗證用戶登錄和注銷時緩存的正確更新,以及對用戶權限變更的處理,雖然這在登錄模塊中是比較次要的測試,但是對于安全性要求較高的系統還是比較重要的;
5. 并發性能測試
在高并發環境下,緩存的并發讀寫可能導致性能問題。測試人員需要驗證緩存在高負載情況下的表現,確保它能夠正確處理并發請求,這對于性能有要求的系統就極為重視。
總結
總之,HTTP緩存是Web性能優化的關鍵組成部分,也是測試工程師所要牢牢掌握的知識點,理解了http緩存有助于我們對web的架構有更深的認識,這樣才能在測試中駕輕就熟。
著我們的應用程序的不斷增長并開始進行復雜的計算時,對速度的需求越來越高(?),所以流程的優化變得必不可少。 當我們忽略這個問題時,我們最終的程序需要花費大量時間并在執行期間消耗大量的系統資源。
緩存是一種優化技術,通過存儲開銷大的函數執行的結果,并在相同的輸入再次出現時返回已緩存的結果,從而加快應用程序的速度。
如果這對你沒有多大意義,那沒關系。 本文深入解釋了為什么需要進行緩存,緩存是什么,如何實現以及何時應該使用緩存。
什么是緩存
緩存是一種優化技術,通過存儲開銷大的函數執行的結果,并在相同的輸入再次出現時返回已緩存的結果,從而加快應用程序的速度。
在這一點上,我們很清楚,緩存的目的是減少執行“昂貴的函數調用”所花費的時間和資源。
什么是昂貴的函數調用?別搞混了,我們不是在這里花錢。在計算機程序的上下文中,我們擁有的兩種主要資源是時間和內存。因此,一個昂貴的函數調用是指一個函數調用中,由于計算量大,在執行過程中大量占用了計算機的資源和時間。
然而,就像對待金錢一樣,我們需要節約。為此,使用緩存來存儲函數調用的結果,以便在將來的時間內快速方便地訪問。
緩存只是一個臨時的數據存儲,它保存數據,以便將來對該數據的請求能夠更快地得到處理。
因此,當一個昂貴的函數被調用一次時,結果被存儲在緩存中,這樣,每當在應用程序中再次調用該函數時,結果就會從緩存中非常快速地取出,而不需要重新進行任何計算。
為什么緩存很重要?
下面是一個實例,說明了緩存的重要性:
想象一下,你正在公園里讀一本封面很吸引人的新小說。每次一個人經過,他們都會被封面吸引,所以他們會問書名和作者。第一次被問到這個問題的時候,你翻開書,讀出書名和作者的名字。現在越來越多的人來這里問同樣的問題。你是一個很好的人,所以你回答所有問題。
你會翻開封面,把書名和作者的名字一一告訴他,還是開始憑記憶回答?哪個能節省你更多的時間?
發現其中的相似之處了嗎?使用記憶法,當函數提供輸入時,它執行所需的計算并在返回值之前將結果存儲到緩存中。如果將來接收到相同的輸入,它就不必一遍又一遍地重復,它只需要從緩存(內存)中提供答案。
緩存是怎么工作的
JavaScript 中的緩存的概念主要建立在兩個概念之上,它們分別是:
閉包
閉包是函數和聲明該函數的詞法環境的組合。
不是很清楚? 我也這么認為。
為了更好的理解,讓我們快速研究一下 JavaScript 中詞法作用域的概念,詞法作用域只是指程序員在編寫代碼時指定的變量和塊的物理位置。如下代碼:
function foo(a) { var b = a + 2; function bar(c) { console.log(a, b, c); } bar(b * 2); } foo(3); // 3, 5, 10
從這段代碼中,我們可以確定三個作用域:
仔細查看上面的代碼,我們注意到函數 foo 可以訪問變量 a 和 b,因為它嵌套在 foo 中。注意,我們成功地存儲了函數 bar 及其運行環境。因此,我們說 bar 在 foo 的作用域上有一個閉包。
你可以在遺傳的背景下理解這一點,即個體有機會獲得并表現出遺傳特征,即使是在他們當前的環境之外,這個邏輯突出了閉包的另一個因素,引出了我們的第二個主要概念。
從函數返回函數
通過接受其他函數作為參數或返回其他函數的函數稱為高階函數。
閉包允許我們在封閉函數的外部調用內部函數,同時保持對封閉函數的詞法作用域的訪問
讓我們對前面的示例中的代碼進行一些調整,以解釋這一點。
function foo(){ var a = 2; function bar() { console.log(a); } return bar; } var baz = foo(); baz();//2
注意函數 foo 如何返回另一個函數 bar。這里我們執行函數 foo 并將返回值賦給baz。但是在本例中,我們有一個返回函數,因此,baz 現在持有對 foo 中定義的bar 函數的引用。
最有趣的是,當我們在 foo 的詞法作用域之外執行函數 baz 時,仍然會得到 a 的值,這怎么可能呢?
請記住,由于閉包的存在,bar 總是可以訪問 foo 中的變量(繼承的特性),即使它是在 foo 的作用域之外執行的。
案例研究:斐波那契數列
斐波那契數列是什么?
斐波那契數列是一組數字,以1 或 0 開頭,后面跟著1,然后根據每個數字等于前兩個數字之和規則進行。如
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, …
或者
1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, …
挑戰:編寫一個函數返回斐波那契數列中的 n 元素,其中的序列是:
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, …]
知道每個值都是前兩個值的和,這個問題的遞歸解是:
function fibonacci(n) { if (n <= 1) { return 1 } return fibonacci(n - 1) + fibonacci(n - 2) }
確實簡潔準確!但是,有一個問題。請注意,當 n 的值到終止遞歸之前,需要做大量的工作和時間,因為序列中存在對某些值的重復求值。
看看下面的圖表,當我們試圖計算 fib(5)時,我們注意到我們反復地嘗試在不同分支的下標 0,1,2,3 處找到 Fibonacci 數,這就是所謂的冗余計算,而這正是緩存所要消除的。
function fibonacci(n, memo) { memomemo = memo || {} if (memo[n]) { return memo[n] } if (n <= 1) { return 1 } return memo[n] = fibonacci(n-1, memo) + fibonacci(n-2, memo) }
在上面的代碼片段中,我們調整函數以接受一個可選參數 memo。我們使用 memo 對象作為緩存來存儲斐波那契數列,并將其各自的索引作為鍵,以便在執行過程中稍后需要時檢索它們。
memomemo = memo || {}
在這里,檢查是否在調用函數時將 memo 作為參數接收。如果有,則初始化它以供使用;如果沒有,則將其設置為空對象。
if (memo[n]) { return memo[n] }
接下來,檢查當前鍵 n 是否有緩存值,如果有,則返回其值。
和之前的解一樣,我們指定了 n 小于等于 1 時的終止遞歸。
最后,我們遞歸地調用n值較小的函數,同時將緩存值(memo)傳遞給每個函數,以便在計算期間使用。這確保了在以前計算并緩存值時,我們不會第二次執行如此昂貴的計算。我們只是從 memo 中取回值。
注意,我們在返回緩存之前將最終結果添加到緩存中。
使用 JSPerf 測試性能
可以使用些鏈接來性能測試。在那里,我們運行一個測試來評估使用這兩種方法執行fibonacci(20) 所需的時間。結果如下:
哇! ! !這讓人很驚訝,使用緩存的 fibonacci 函數是最快的。然而,這一數字相當驚人。它執行 126,762 ops/sec,這遠遠大于執行 1,751 ops/sec 的純遞歸解決方案,并且比較沒有緩存的遞歸速度大約快 99%。
注:“ops/sec”表示每秒的操作次數,就是一秒鐘內預計要執行的測試次數。
現在我們已經看到了緩存在函數級別上對應用程序的性能有多大的影響。這是否意味著對于應用程序中的每個昂貴函數,我們都必須創建一個修改后的變量來維護內部緩存?
不,回想一下,我們通過從函數返回函數來了解到,即使在外部執行它們,它們也會導致它們繼承父函數的范圍,這使得可以將某些特征和屬性從封閉函數傳遞到返回的函數。
使用函數的方式
在下面的代碼片段中,我們創建了一個高階的函數 memoizer。有了這個函數,將能夠輕松地將緩存應用到任何函數。
function memoizer(fun) { let cache = {} return function (n) { if (cache[n] != undefined) { return cache[n] } else { let result = fun(n) cache[n] = result return result } } }
上面,我們簡單地創建一個名為 memoizer 的新函數,它接受將函數 fun 作為參數進行緩存。在函數中,我們創建一個緩存對象來存儲函數執行的結果,以便將來使用。
從 memoizer 函數中,我們返回一個新函數,根據上面討論的閉包原則,這個函數無論在哪里執行都可以訪問 cache。
在返回的函數中,我們使用 if..else 語句檢查是否已經有指定鍵(參數) n 的緩存值。如果有,則取出并返回它。如果沒有,我們使用函數來計算結果,以便緩存。然后,我們使用適當的鍵 n 將結果添加到緩存中,以便以后可以從那里訪問它。最后,我們返回了計算結果。
很順利!
要將 memoizer 函數應用于最初遞歸的 fibonacci 函數,我們調用 memoizer 函數,將 fibonacci 函數作為參數傳遞進去。
const fibonacciMemoFunction = memoizer(fibonacciRecursive)
測試 memoizer 函數
當我們將 memoizer 函數與上面的例子進行比較時,結果如下:
memoizer 函數以 42,982,762 ops/sec 的速度提供了最快的解決方案,比之前考慮的解決方案速度要快 100%。
關于緩存,我們已經說明什么是緩存 、為什么要有緩存和如何實現緩存。現在我們來看看什么時候使用緩存。
何時使用緩存
當然,使用緩存效率是級高的,你現在可能想要緩存所有的函數,這可能會變得非常無益。以下幾種情況下,適合使用緩存:
緩存庫
總結
使用緩存方法 ,我們可以防止函數調用函數來反復計算相同的結果,現在是你把這些知識付諸實踐的時候了。
天下數據是國內屈指可數的擁有多處海外自建機房的新型IDC服務商,被業界公認為“中國IDC行業首選品牌”。
天下數據與全球近120多個國家頂級機房直接合作,包括香港、美國、韓國、日本、臺灣、新加坡、荷蘭、法國、英國、德國、埃及、南非、巴西、印度、越南等國家和地區的服務器、云服務器的服務.
除提供傳統的IDC產品外,天下數據的主要職責是為大中型企業提供更精細、安全、滿足個性需求的定制化服務器解決方案,特別是在直銷、金融、視頻、流媒體、游戲、電子商務、區塊鏈、快消、物聯網、大數據等諸多行業,為廣大客戶解決服務器租用中遇到的各種問題。
言
本篇文章主要介紹了前端HTML5幾種存儲方式的總結 ,主要包括本地存儲localstorage,本地存儲sessionstorage,離線緩存(application cache),Web SQL,IndexedDB。有興趣的可以了解一下。
正文開始~
總體情況
h5之前,存儲主要是用cookies。cookies缺點有在請求頭上帶著數據,大小是4k之內。主Domain污染。
主要應用:購物車、客戶登錄
對于IE瀏覽器有UserData,大小是64k,只有IE瀏覽器支持。
目標
存儲方式:
以鍵值對(Key-Value)的方式存儲,永久存儲,永不失效,除非手動刪除。
大小:
每個域名5M
支持情況:
注意:IE9 localStorage不支持本地文件,需要將項目署到服務器,才可以支持!
if(window.localStorage){ alert('This browser supports localStorage'); }else{ alert('This browser does NOT support localStorage'); }
常用的API:
getItem //取記錄
setIten//設置記錄
removeItem//移除記錄
key//取key所對應的值
clear//清除記錄
存儲的內容:
數組,圖片,json,樣式,腳本。。。(只要是能序列化成字符串的內容都可以存儲)
2.本地存儲sessionstorage
HTML5 的本地存儲 API 中的 localStorage 與 sessionStorage 在使用方法上是相同的,區別在于 sessionStorage 在關閉頁面后即被清空,而 localStorage 則會一直保存。
3.離線緩存(application cache)
本地緩存應用所需的文件
使用方法:
①配置manifest文件
頁面上:
<!DOCTYPE HTML> <html manifest="demo.appcache"> ... </html>
Manifest 文件:
manifest 文件是簡單的文本文件,它告知瀏覽器被緩存的內容(以及不緩存的內容)。
manifest 文件可分為三個部分:
①CACHE MANIFEST - 在此標題下列出的文件將在首次下載后進行緩存
②NETWORK - 在此標題下列出的文件需要與服務器的連接,且不會被緩存
③FALLBACK - 在此標題下列出的文件規定當頁面無法訪問時的回退頁面(比如 404 頁面)
完整demo:
CACHE MANIFEST # 2016-07-24 v1.0.0 /theme.css /main.js NETWORK: login.jsp FALLBACK: /html/ /offline.html
服務器上:manifest文件需要配置正確的MIME-type,即 "text/cache-manifest"。
如Tomcat:
<mime-mapping> <extension>manifest</extension> <mime-type>text/cache-manifest</mime-type> </mime-mapping>
常用API:
核心是applicationCache對象,有個status屬性,表示應用緩存的當前狀態:
0(UNCACHED) : 無緩存, 即沒有與頁面相關的應用緩存
1(IDLE) : 閑置,即應用緩存未得到更新
2 (CHECKING) : 檢查中,即正在下載描述文件并檢查更新
3 (DOWNLOADING) : 下載中,即應用緩存正在下載描述文件中指定的資源
4 (UPDATEREADY) : 更新完成,所有資源都已下載完畢
5 (IDLE) : 廢棄,即應用緩存的描述文件已經不存在了,因此頁面無法再訪問應用緩存
相關的事件:
表示應用緩存狀態的改變:
checking : 在瀏覽器為應用緩存查找更新時觸發
error : 在檢查更新或下載資源期間發送錯誤時觸發
noupdate : 在檢查描述文件發現文件無變化時觸發
downloading : 在開始下載應用緩存資源時觸發
progress:在文件下載應用緩存的過程中持續不斷地下載地觸發
updateready : 在頁面新的應用緩存下載完畢觸發
cached : 在應用緩存完整可用時觸發
Application Cache的三個優勢:
① 離線瀏覽
② 提升頁面載入速度
③ 降低服務器壓力
注意事項:
1. 瀏覽器對緩存數據的容量限制可能不太一樣(某些瀏覽器設置的限制是每個站點 5MB)
2. 如果manifest文件,或者內部列舉的某一個文件不能正常下載,整個更新過程將視為失敗,瀏覽器繼續全部使用老的緩存
3. 引用manifest的html必須與manifest文件同源,在同一個域下
4. 瀏覽器會自動緩存引用manifest文件的HTML文件,這就導致如果改了HTML內容,也需要更新版本才能做到更新。
5. manifest文件中CACHE則與NETWORK,FALLBACK的位置順序沒有關系,如果是隱式聲明需要在最前面
6. FALLBACK中的資源必須和manifest文件同源
7. 更新完版本后,必須刷新一次才會啟動新版本(會出現重刷一次頁面的情況),需要添加監聽版本事件。
8. 站點中的其他頁面即使沒有設置manifest屬性,請求的資源如果在緩存中也從緩存中訪問
9. 當manifest文件發生改變時,資源請求本身也會觸發更新
離線緩存與傳統瀏覽器緩存區別:
1. 離線緩存是針對整個應用,瀏覽器緩存是單個文件
2. 離線緩存斷網了還是可以打開頁面,瀏覽器緩存不行
3. 離線緩存可以主動通知瀏覽器更新資源
4.Web SQL
關系數據庫,通過SQL語句訪問
Web SQL 數據庫 API 并不是 HTML5 規范的一部分,但是它是一個獨立的規范,引入了一組使用 SQL 操作客戶端數據庫的 APIs。
支持情況:
Web SQL 數據庫可以在最新版的 Safari, Chrome 和 Opera 瀏覽器中工作。
核心方法:
①openDatabase:這個方法使用現有的數據庫或者新建的數據庫創建一個數據庫對象。
②transaction:這個方法讓我們能夠控制一個事務,以及基于這種情況執行提交或者回滾。
③executeSql:這個方法用于執行實際的 SQL 查詢。
打開數據庫:
var db = openDatabase('mydb', '1.0', 'Test DB', 2 * 1024 * 1024,fn); //openDatabase() 方法對應的五個參數分別為:數據庫名稱、版本號、描述文本、數據庫大小、創建回調
執行查詢操作:
var db = openDatabase('mydb', '1.0', 'Test DB', 2 * 1024 * 1024); db.transaction(function (tx) { tx.executeSql('CREATE TABLE IF NOT EXISTS WIN (id unique, name)'); });
插入數據:
var db = openDatabase('mydb', '1.0', 'Test DB', 2 * 1024 * 1024); db.transaction(function (tx) { tx.executeSql('CREATE TABLE IF NOT EXISTS WIN (id unique, name)'); tx.executeSql('INSERT INTO WIN (id, name) VALUES (1, "winty")'); tx.executeSql('INSERT INTO WIN (id, name) VALUES (2, "LuckyWinty")'); });
讀取數據:
db.transaction(function (tx) { tx.executeSql('SELECT * FROM WIN', [], function (tx, results) { var len = results.rows.length, i; msg = "<p>查詢記錄條數: " + len + "</p>"; document.querySelector('#status').innerHTML += msg; for (i = 0; i < len; i++){ alert(results.rows.item(i).name ); } }, null); });
由這些操作可以看出,基本上都是用SQL語句進行數據庫的相關操作,如果你會MySQL的話,這個應該比較容易用。
索引數據庫 (IndexedDB) API(作為 HTML5 的一部分)對創建具有豐富本地存儲數據的數據密集型的離線 HTML5 Web 應用程序很有用。同時它還有助于本地緩存數據,使傳統在線 Web 應用程序(比如移動 Web 應用程序)能夠更快地運行和響應。
異步API:
在IndexedDB大部分操作并不是我們常用的調用方法,返回結果的模式,而是請求——響應的模式,比如打開數據庫的操作
這樣,我們打開數據庫的時候,實質上返回了一個DB對象,而這個對象就在result中。由上圖可以看出,除了result之外。還有幾個重要的屬性就是onerror、onsuccess、onupgradeneeded(我們請求打開的數據庫的版本號和已經存在的數據庫版本號不一致的時候調用)。這就類似于我們的ajax請求那樣。我們發起了這個請求之后并不能確定它什么時候才請求成功,所以需要在回調中處理一些邏輯。
關閉與刪除:
function closeDB(db){ db.close(); } function deleteDB(name){ indexedDB.deleteDatabase(name); }
數據存儲:
indexedDB中沒有表的概念,而是objectStore,一個數據庫中可以包含多個objectStore,objectStore是一個靈活的數據結構,可以存放多種類型數據。也就是說一個objectStore相當于一張表,里面存儲的每條數據和一個鍵相關聯。
我們可以使用每條記錄中的某個指定字段作為鍵值(keyPath),也可以使用自動生成的遞增數字作為鍵值(keyGenerator),也可以不指定。選擇鍵的類型不同,objectStore可以存儲的數據結構也有差異。
天下數據是國內屈指可數的擁有多處海外自建機房的新型IDC服務商,被業界公認為“中國IDC行業首選品牌”。
天下數據與全球近120多個國家頂級機房直接合作,提供包括香港、美國、韓國、日本、臺灣、新加坡、荷蘭、法國、英國、德國、埃及、南非、巴西、印度、越南等國家和地區的服務器、云服務器的租用服務,需要的請聯系天下數據客服!
除提供傳統的IDC產品外,天下數據的主要職責是為大中型企業提供更精細、安全、滿足個性需求的定制化服務器解決方案,特別是在直銷、金融、視頻、流媒體、游戲、電子商務、區塊鏈、快消、物聯網、大數據等諸多行業,為廣大客戶解決服務器租用中遇到的各種問題。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。