自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

77.9K 的 Axios 項目有哪些值得借鑒的地方

系統(tǒng)
Axios 是一個基于 Promise 的 HTTP 客戶端,同時支持瀏覽器和 Node.js 環(huán)境。它是一個優(yōu)秀的 HTTP 客戶端,被廣泛地應(yīng)用在大量的 Web 項目中。

Axios 是一個基于 Promise 的 HTTP 客戶端,同時支持瀏覽器和 Node.js 環(huán)境。它是一個優(yōu)秀的 HTTP 客戶端,被廣泛地應(yīng)用在大量的 Web 項目中。

由上圖可知,Axios 項目的 Star 數(shù)為 「77.9K」,F(xiàn)ork 數(shù)也高達 「7.3K」,是一個很優(yōu)秀的開源項目,所以接下來阿寶哥將帶大家一起來分析 Axios 項目中一些值得借鑒的地方。

閱讀完本文,你將了解以下內(nèi)容:

  • HTTP 攔截器的設(shè)計與實現(xiàn);
  • HTTP 適配器的設(shè)計與實現(xiàn);
  • 如何防御 CSRF 攻擊。

下面我們從簡單的開始,先來了解一下 Axios。

一、Axios 簡介
Axios 是一個基于 Promise 的 HTTP 客戶端,擁有以下特性:

  • 支持 Promise API;
  • 能夠攔截請求和響應(yīng);
  • 能夠轉(zhuǎn)換請求和響應(yīng)數(shù)據(jù);
  • 客戶端支持防御 CSRF 攻擊;
  • 同時支持瀏覽器和 Node.js 環(huán)境;
  • 能夠取消請求及自動轉(zhuǎn)換 JSON 數(shù)據(jù)。

在瀏覽器端 Axios 支持大多數(shù)主流的瀏覽器,比如 Chrome、Firefox、Safari 和 IE 11。此外,Axios 還擁有自己的生態(tài):

(數(shù)據(jù)來源 —— https://github.com/axios/axios/blob/master/ECOSYSTEM.md)

簡單介紹完 Axios,我們來分析一下它提供的一個核心功能 —— 攔截器。

二、HTTP 攔截器的設(shè)計與實現(xiàn)
2.1 攔截器簡介
對于大多數(shù) SPA 應(yīng)用程序來說, 通常會使用 token 進行用戶的身份認證。這就要求在認證通過后,我們需要在每個請求上都攜帶認證信息。針對這個需求,為了避免為每個請求單獨處理,我們可以通過封裝統(tǒng)一的 request 函數(shù)來為每個請求統(tǒng)一添加 token 信息。

但后期如果需要為某些 GET 請求設(shè)置緩存時間或者控制某些請求的調(diào)用頻率的話,我們就需要不斷修改 request 函數(shù)來擴展對應(yīng)的功能。此時,如果在考慮對響應(yīng)進行統(tǒng)一處理的話,我們的 request 函數(shù)將變得越來越龐大,也越來越難維護。那么對于這個問題,該如何解決呢?Axios 為我們提供了解決方案 —— 攔截器。

Axios 是一個基于 Promise 的 HTTP 客戶端,而 HTTP 協(xié)議是基于請求和響應(yīng):

所以 Axios 提供了請求攔截器和響應(yīng)攔截器來分別處理請求和響應(yīng),它們的作用如下:

  • 請求攔截器:該類攔截器的作用是在請求發(fā)送前統(tǒng)一執(zhí)行某些操作,比如在請求頭中添加 token 字段。
  • 響應(yīng)攔截器:該類攔截器的作用是在接收到服務(wù)器響應(yīng)后統(tǒng)一執(zhí)行某些操作,比如發(fā)現(xiàn)響應(yīng)狀態(tài)碼為 401 時,自動跳轉(zhuǎn)到登錄頁。

在 Axios 中設(shè)置攔截器很簡單,通過 axios.interceptors.request 和 axios.interceptors.response 對象提供的 use 方法,就可以分別設(shè)置請求攔截器和響應(yīng)攔截器:

  1. // 添加請求攔截器 
  2. axios.interceptors.request.use(function (config) { 
  3.   config.headers.token = 'added by interceptor'
  4.   return config; 
  5. }); 
  6.  
  7. // 添加響應(yīng)攔截器 
  8. axios.interceptors.response.use(function (data) { 
  9.   data.data = data.data + ' - modified by interceptor'
  10.   return data; 
  11. }); 

那么攔截器是如何工作的呢?在看具體的代碼之前,我們先來分析一下它的設(shè)計思路。Axios 的作用是用于發(fā)送 HTTP 請求,而請求攔截器和響應(yīng)攔截器的本質(zhì)都是一個實現(xiàn)特定功能的函數(shù)。

我們可以按照功能把發(fā)送 HTTP 請求拆解成不同類型的子任務(wù),比如有用于處理請求配置對象的子任務(wù),用于發(fā)送 HTTP 請求的子任務(wù)和用于處理響應(yīng)對象的子任務(wù)。當(dāng)我們按照指定的順序來執(zhí)行這些子任務(wù)時,就可以完成一次完整的 HTTP 請求。

了解完這些,接下來我們將從 「任務(wù)注冊、任務(wù)編排和任務(wù)調(diào)度」 三個方面來分析 Axios 攔截器的實現(xiàn)。

2.2 任務(wù)注冊
通過前面攔截器的使用示例,我們已經(jīng)知道如何注冊請求攔截器和響應(yīng)攔截器,其中請求攔截器用于處理請求配置對象的子任務(wù),而響應(yīng)攔截器用于處理響應(yīng)對象的子任務(wù)。要搞清楚任務(wù)是如何注冊的,就需要了解 axios 和 axios.interceptors 對象。

  1. // lib/axios.js 
  2. function createInstance(defaultConfig) { 
  3.   var context = new Axios(defaultConfig); 
  4.   var instance = bind(Axios.prototype.request, context); 
  5.  
  6.   // Copy axios.prototype to instance 
  7.   utils.extend(instance, Axios.prototype, context); 
  8.   // Copy context to instance 
  9.   utils.extend(instance, context); 
  10.   return instance; 
  11.  
  12. // Create the default instance to be exported 
  13. var axios = createInstance(defaults); 

在 Axios 的源碼中,我們找到了 axios 對象的定義,很明顯默認的 axios 實例是通過 createInstance 方法創(chuàng)建的,該方法最終返回的是 Axios.prototype.request 函數(shù)對象。同時,我們發(fā)現(xiàn)了 Axios 的構(gòu)造函數(shù):

  1. // lib/core/Axios.js 
  2. function Axios(instanceConfig) { 
  3.   this.defaults = instanceConfig; 
  4.   this.interceptors = { 
  5.     request: new InterceptorManager(), 
  6.     response: new InterceptorManager() 
  7.   }; 

在構(gòu)造函數(shù)中,我們找到了 axios.interceptors 對象的定義,也知道了 interceptors.request 和 interceptors.response 對象都是 InterceptorManager 類的實例。因此接下來,進一步分析 InterceptorManager 構(gòu)造函數(shù)及相關(guān)的 use 方法就可以知道任務(wù)是如何注冊的:

  1. // lib/core/InterceptorManager.js 
  2. function InterceptorManager() { 
  3.   this.handlers = []; 
  4.  
  5. InterceptorManager.prototype.use = function use(fulfilled, rejected) { 
  6.   this.handlers.push({ 
  7.     fulfilled: fulfilled, 
  8.     rejected: rejected 
  9.   }); 
  10.   // 返回當(dāng)前的索引,用于移除已注冊的攔截器 
  11.   return this.handlers.length - 1; 
  12. }; 

通過觀察 use 方法,我們可知注冊的攔截器都會被保存到 InterceptorManager 對象的 handlers 屬性中。下面我們用一張圖來總結(jié)一下 Axios 對象與 InterceptorManager 對象的內(nèi)部結(jié)構(gòu)與關(guān)系:

2.3 任務(wù)編排
現(xiàn)在我們已經(jīng)知道如何注冊攔截器任務(wù),但僅僅注冊任務(wù)是不夠,我們還需要對已注冊的任務(wù)進行編排,這樣才能確保任務(wù)的執(zhí)行順序。這里我們把完成一次完整的 HTTP 請求分為處理請求配置對象、發(fā)起 HTTP 請求和處理響應(yīng)對象 3 個階段。

接下來我們來看一下 Axios 如何發(fā)請求的:

  1. axios({ 
  2.   url: '/hello'
  3.   method: 'get'
  4. }).then(res =>{ 
  5.   console.log('axios res: ', res) 
  6.   console.log('axios res.data: ', res.data) 
  7. }) 

通過前面的分析,我們已經(jīng)知道 axios 對象對應(yīng)的是 Axios.prototype.request 函數(shù)對象,該函數(shù)的具體實現(xiàn)如下:

  1. // lib/core/Axios.js 
  2. Axios.prototype.request = function request(config) { 
  3.   config = mergeConfig(this.defaults, config); 
  4.  
  5.   // 省略部分代碼 
  6.   var chain = [dispatchRequest, undefined]; 
  7.   var promise = Promise.resolve(config); 
  8.  
  9.   // 任務(wù)編排 
  10.   this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) { 
  11.     chain.unshift(interceptor.fulfilled, interceptor.rejected); 
  12.   }); 
  13.  
  14.   this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) { 
  15.     chain.push(interceptor.fulfilled, interceptor.rejected); 
  16.   }); 
  17.  
  18.   // 任務(wù)調(diào)度 
  19.   while (chain.length) { 
  20.     promise = promise.then(chain.shift(), chain.shift()); 
  21.   } 
  22.  
  23.   return promise; 
  24. }; 

任務(wù)編排的代碼比較簡單,我們來看一下任務(wù)編排前和任務(wù)編排后的對比圖:

2.4 任務(wù)調(diào)度
任務(wù)編排完成后,要發(fā)起 HTTP 請求,我們還需要按編排后的順序執(zhí)行任務(wù)調(diào)度。在 Axios 中具體的調(diào)度方式很簡單,具體如下所示:

  1. // lib/core/Axios.js 
  2. xios.prototype.request = function request(config) { 
  3.  // 省略部分代碼 
  4.  var promise = Promise.resolve(config); 
  5.  while (chain.length) { 
  6.    promise = promise.then(chain.shift(), chain.shift()); 
  7.  } 

因為 chain 是數(shù)組,所以通過 while 語句我們就可以不斷地取出設(shè)置的任務(wù),然后組裝成 Promise 調(diào)用鏈從而實現(xiàn)任務(wù)調(diào)度,對應(yīng)的處理流程如下圖所示:

下面我們來回顧一下 Axios 攔截器完整的使用流程:

  1. // 添加請求攔截器 —— 處理請求配置對象 
  2. axios.interceptors.request.use(function (config) { 
  3.   config.headers.token = 'added by interceptor'
  4.   return config; 
  5. }); 
  6.  
  7. // 添加響應(yīng)攔截器 —— 處理響應(yīng)對象 
  8. axios.interceptors.response.use(function (data) { 
  9.   data.data = data.data + ' - modified by interceptor'
  10.   return data; 
  11. }); 
  12.  
  13. axios({ 
  14.   url: '/hello'
  15.   method: 'get'
  16. }).then(res =>{ 
  17.   console.log('axios res.data: ', res.data) 
  18. }) 

介紹完 Axios 的攔截器,我們來總結(jié)一下它的優(yōu)點。Axios 通過提供攔截器機制,讓開發(fā)者可以很容易在請求的生命周期中自定義不同的處理邏輯。

此外,也可以通過攔截器機制來靈活地擴展 Axios 的功能,比如 Axios 生態(tài)中列舉的 axios-response-logger 和 axios-debug-log 這兩個庫。

參考 Axios 攔截器的設(shè)計模型,我們就可以抽出以下通用的任務(wù)處理模型:

三、HTTP 適配器的設(shè)計與實現(xiàn)
3.1 默認 HTTP 適配器
Axios 同時支持瀏覽器和 Node.js 環(huán)境,對于瀏覽器環(huán)境來說,我們可以通過 XMLHttpRequest 或 fetch API 來發(fā)送 HTTP 請求,而對于 Node.js 環(huán)境來說,我們可以通過 Node.js 內(nèi)置的 http 或 https 模塊來發(fā)送 HTTP 請求。

為了支持不同的環(huán)境,Axios 引入了適配器。在 HTTP 攔截器設(shè)計部分,我們看到了一個 dispatchRequest 方法,該方法用于發(fā)送 HTTP 請求,它的具體實現(xiàn)如下所示:

  1. // lib/core/dispatchRequest.js 
  2. module.exports = function dispatchRequest(config) { 
  3.   // 省略部分代碼 
  4.   var adapter = config.adapter || defaults.adapter; 
  5.    
  6.   return adapter(config).then(function onAdapterResolution(response) { 
  7.     // 省略部分代碼 
  8.     return response; 
  9.   }, function onAdapterRejection(reason) { 
  10.     // 省略部分代碼 
  11.     return Promise.reject(reason); 
  12.   }); 
  13. }; 

通過查看以上的 dispatchRequest 方法,我們可知 Axios 支持自定義適配器,同時也提供了默認的適配器。對于大多數(shù)場景,我們并不需要自定義適配器,而是直接使用默認的適配器。因此,默認的適配器就會包含瀏覽器和 Node.js 環(huán)境的適配代碼,其具體的適配邏輯如下所示:

  1. // lib/defaults.js 
  2. var defaults = { 
  3.   adapter: getDefaultAdapter(), 
  4.   xsrfCookieName: 'XSRF-TOKEN'
  5.   xsrfHeaderName: 'X-XSRF-TOKEN'
  6.   //... 
  7.  
  8. function getDefaultAdapter() { 
  9.   var adapter; 
  10.   if (typeof XMLHttpRequest !== 'undefined') { 
  11.     // For browsers use XHR adapter 
  12.     adapter = require('./adapters/xhr'); 
  13.   } else if (typeof process !== 'undefined' &&  
  14.     Object.prototype.toString.call(process) === '[object process]') { 
  15.     // For node use HTTP adapter 
  16.     adapter = require('./adapters/http'); 
  17.   } 
  18.   return adapter; 

在 getDefaultAdapter 方法中,首先通過平臺中特定的對象來區(qū)分不同的平臺,然后再導(dǎo)入不同的適配器,具體的代碼比較簡單,這里就不展開介紹。

3.2 自定義適配器
其實除了默認的適配器外,我們還可以自定義適配器。那么如何自定義適配器呢?這里我們可以參考 Axios 提供的示例:

  1. var settle = require('./../core/settle'); 
  2. module.exports = function myAdapter(config) { 
  3.   // 當(dāng)前時機點: 
  4.   //  - config配置對象已經(jīng)與默認的請求配置合并 
  5.   //  - 請求轉(zhuǎn)換器已經(jīng)運行 
  6.   //  - 請求攔截器已經(jīng)運行 
  7.    
  8.   // 使用提供的config配置對象發(fā)起請求 
  9.   // 根據(jù)響應(yīng)對象處理Promise的狀態(tài) 
  10.   return new Promise(function(resolve, reject) { 
  11.     var response = { 
  12.       data: responseData, 
  13.       status: request.status, 
  14.       statusText: request.statusText, 
  15.       headers: responseHeaders, 
  16.       config: config, 
  17.       request: request 
  18.     }; 
  19.  
  20.     settle(resolve, reject, response); 
  21.  
  22.     // 此后: 
  23.     //  - 響應(yīng)轉(zhuǎn)換器將會運行 
  24.     //  - 響應(yīng)攔截器將會運行 
  25.   }); 

在以上示例中,我們主要關(guān)注轉(zhuǎn)換器、攔截器的運行時機點和適配器的基本要求。比如當(dāng)調(diào)用自定義適配器之后,需要返回 Promise 對象。這是因為 Axios 內(nèi)部是通過 Promise 鏈?zhǔn)秸{(diào)用來完成請求調(diào)度,不清楚的小伙伴可以重新閱讀 “攔截器的設(shè)計與實現(xiàn)” 部分的內(nèi)容。

現(xiàn)在我們已經(jīng)知道如何自定義適配器了,那么自定義適配器有什么用呢?在 Axios 生態(tài)中,阿寶哥發(fā)現(xiàn)了 axios-mock-adapter 這個庫,該庫通過自定義適配器,讓開發(fā)者可以輕松地模擬請求。對應(yīng)的使用示例如下所示:

  1. var axios = require("axios"); 
  2. var MockAdapter = require("axios-mock-adapter"); 
  3.  
  4. // 在默認的Axios實例上設(shè)置mock適配器 
  5. var mock = new MockAdapter(axios); 
  6.  
  7. // 模擬 GET /users 請求 
  8. mock.onGet("/users").reply(200, { 
  9.   users: [{ id: 1, name"John Smith" }], 
  10. }); 
  11.  
  12. axios.get("/users").then(function (response) { 
  13.   console.log(response.data); 
  14. }); 

對 MockAdapter 感興趣的小伙伴,可以自行了解一下 axios-mock-adapter 這個庫。到這里我們已經(jīng)介紹了 Axios 的攔截器與適配器,下面阿寶哥用一張圖來總結(jié)一下 Axios 使用請求攔截器和響應(yīng)攔截器后,請求的處理流程:

四、CSRF 防御
4.1 CSRF 簡介
「跨站請求偽造」(Cross-site request forgery),通常縮寫為 「CSRF」 或者 「XSRF」, 是一種挾制用戶在當(dāng)前已登錄的 Web 應(yīng)用程序上執(zhí)行非本意的操作的攻擊方法。

跨站請求攻擊,簡單地說,是攻擊者通過一些技術(shù)手段欺騙用戶的瀏覽器去訪問一個自己曾經(jīng)認證過的網(wǎng)站并運行一些操作(如發(fā)郵件,發(fā)消息,甚至財產(chǎn)操作如轉(zhuǎn)賬和購買商品)。由于瀏覽器曾經(jīng)認證過,所以被訪問的網(wǎng)站會認為是真正的用戶操作而去運行。

為了讓小伙伴更好地理解上述的內(nèi)容,阿寶哥畫了一張跨站請求攻擊示例圖:

在上圖中攻擊者利用了 Web 中用戶身份驗證的一個漏洞:「簡單的身份驗證只能保證請求發(fā)自某個用戶的瀏覽器,卻不能保證請求本身是用戶自愿發(fā)出的」。既然存在以上的漏洞,那么我們應(yīng)該怎么進行防御呢?接下來我們來介紹一些常見的 CSRF 防御措施。

4.2 CSRF 防御措施
4.2.1 檢查 Referer 字段
HTTP 頭中有一個 Referer 字段,這個字段用以標(biāo)明請求來源于哪個地址?!冈谔幚砻舾袛?shù)據(jù)請求時,通常來說,Referer 字段應(yīng)和請求的地址位于同一域名下」。

以示例中商城操作為例,Referer 字段地址通常應(yīng)該是商城所在的網(wǎng)頁地址,應(yīng)該也位于 www.semlinker.com 之下。而如果是 CSRF 攻擊傳來的請求,Referer 字段會是包含惡意網(wǎng)址的地址,不會位于 www.semlinker.com 之下,這時候服務(wù)器就能識別出惡意的訪問。

這種辦法簡單易行,僅需要在關(guān)鍵訪問處增加一步校驗。但這種辦法也有其局限性,因其完全依賴瀏覽器發(fā)送正確的 Referer 字段。雖然 HTTP 協(xié)議對此字段的內(nèi)容有明確的規(guī)定,但并無法保證來訪的瀏覽器的具體實現(xiàn),亦無法保證瀏覽器沒有安全漏洞影響到此字段。并且也存在攻擊者攻擊某些瀏覽器,篡改其 Referer 字段的可能。

4.2.2 同步表單 CSRF 校驗
CSRF 攻擊之所以能夠成功,是因為服務(wù)器無法區(qū)分正常請求和攻擊請求。針對這個問題我們可以要求所有的用戶請求都攜帶一個 CSRF 攻擊者無法獲取到的 token。對于 CSRF 示例圖中的表單攻擊,我們可以使用 「同步表單 CSRF 校驗」 的防御措施。

「同步表單 CSRF 校驗」 就是在返回頁面時將 token 渲染到頁面上,在 form 表單提交的時候通過隱藏域或者作為查詢參數(shù)把 CSRF token 提交到服務(wù)器。比如,在同步渲染頁面時,在表單請求中增加一個 _csrf 的查詢參數(shù),這樣當(dāng)用戶在提交這個表單的時候就會將 CSRF token 提交上來:

  1. <form method="POST" action="/upload?_csrf={{由服務(wù)端生成}}" enctype="multipart/form-data"
  2.   用戶名: <input name="name" /> 
  3.   選擇頭像: <input name="file" type="file" /> 
  4.   <button type="submit">提交</button> 
  5. </form> 

4.2.3 雙重 Cookie 防御
「雙重 Cookie 防御」 就是將 token 設(shè)置在 Cookie 中,在提交(POST、PUT、PATCH、DELETE)等請求時提交 Cookie,并通過請求頭或請求體帶上 Cookie 中已設(shè)置的 token,服務(wù)端接收到請求后,再進行對比校驗。

下面我們以 jQuery 為例,來看一下如何設(shè)置 CSRF token:

  1. let csrfToken = Cookies.get('csrfToken'); 
  2.  
  3. function csrfSafeMethod(method) { 
  4.   // 以下HTTP方法不需要進行CSRF防護 
  5.   return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); 
  6.  
  7. $.ajaxSetup({ 
  8.   beforeSend: function(xhr, settings) { 
  9.     if (!csrfSafeMethod(settings.type) && !this.crossDomain) { 
  10.       xhr.setRequestHeader('x-csrf-token', csrfToken); 
  11.     } 
  12.   }, 
  13. }); 

介紹完 CSRF 攻擊的方式和防御手段,最后我們來看一下 Axios 是如何防御 CSRF 攻擊的。

4.3 Axios CSRF 防御
Axios 提供了 xsrfCookieName 和 xsrfHeaderName 兩個屬性來分別設(shè)置 CSRF 的 Cookie 名稱和 HTTP 請求頭的名稱,它們的默認值如下所示:

  1. // lib/defaults.js 
  2. var defaults = { 
  3.   adapter: getDefaultAdapter(), 
  4.  
  5.   // 省略部分代碼 
  6.   xsrfCookieName: 'XSRF-TOKEN'
  7.   xsrfHeaderName: 'X-XSRF-TOKEN'
  8. }; 

前面我們已經(jīng)知道在不同的平臺中,Axios 使用不同的適配器來發(fā)送 HTTP 請求,這里我們以瀏覽器平臺為例,來看一下 Axios 如何防御 CSRF 攻擊:

  1. // lib/adapters/xhr.js 
  2. module.exports = function xhrAdapter(config) { 
  3.   return new Promise(function dispatchXhrRequest(resolve, reject) { 
  4.     var requestHeaders = config.headers; 
  5.      
  6.     var request = new XMLHttpRequest(); 
  7.     // 省略部分代碼 
  8.      
  9.     // 添加xsrf頭部 
  10.     if (utils.isStandardBrowserEnv()) { 
  11.       var xsrfValue = (config.withCredentials || isURLSameOrigin(fullPath)) && config.xsrfCookieName ? 
  12.         cookies.read(config.xsrfCookieName) : 
  13.         undefined; 
  14.  
  15.       if (xsrfValue) { 
  16.         requestHeaders[config.xsrfHeaderName] = xsrfValue; 
  17.       } 
  18.     } 
  19.  
  20.     request.send(requestData); 
  21.   }); 
  22. }; 

看完以上的代碼,相信小伙伴們就已經(jīng)知道答案了,原來 Axios 內(nèi)部是使用 「雙重 Cookie 防御」 的方案來防御 CSRF 攻擊。

好的,到這里本文的主要內(nèi)容都已經(jīng)介紹完了,其實 Axios 項目還有一些值得我們借鑒的地方,比如 CancelToken 的設(shè)計、異常處理機制等,感興趣的小伙伴可以自行學(xué)習(xí)一下。

五、參考資源
Github - axios
維基百科 - 跨站請求偽造
Egg - 安全威脅 CSRF 的防范

 

責(zé)任編輯:姜華 來源: 全棧修仙之路
相關(guān)推薦

2017-03-22 12:58:58

WP系統(tǒng)Windows動態(tài)磁貼

2017-03-20 19:12:24

WPWindows PhoOLED

2022-08-02 15:18:00

React開源項目

2015-11-10 16:13:22

數(shù)據(jù)中心節(jié)能

2009-08-03 13:02:44

Windows7VistaUbuntu

2009-12-07 09:26:00

LinuxWindows

2009-12-12 11:01:30

LinuxWindows系統(tǒng)特性

2023-08-14 08:34:14

GolangHttp

2022-11-30 08:17:41

JVM調(diào)優(yōu)技巧

2019-10-16 08:00:00

網(wǎng)管員IT網(wǎng)絡(luò)

2020-12-24 16:56:14

首席執(zhí)行官遠程工作

2022-05-25 14:35:57

加密貨幣比特幣以太坊

2013-06-24 09:25:06

無線路由器路由器無線網(wǎng)絡(luò)

2022-07-18 08:00:00

邊緣計算經(jīng)驗開發(fā)

2013-12-23 15:00:14

Windows 8.2Win8.2

2012-08-09 13:38:39

API

2020-07-14 08:45:13

Flink特性jira

2020-10-29 12:55:47

編程代碼開發(fā)

2014-01-16 10:01:29

虛擬運營商

2011-01-06 09:17:10

創(chuàng)新HadoopSharePoint
點贊
收藏

51CTO技術(shù)棧公眾號