【轉】對Django架構架構和Request/Response處理流程的分析

來源:互聯網
上載者:User

標籤:

本文轉載於瘋狂的螞蟻。

一、 處理過程的核心概念

如所示django的總覽圖,整體上把握以下django的組成:

核心在於中介軟體middleware,django所有的請求、返回都由中介軟體來完成。

中介軟體,就是處理HTTP的request和response的,類似外掛程式,比如有Request中介軟體、view中介軟體、response中介軟體、exception中介軟體等,Middleware都需要在 “project/settings.py” 中 MIDDLEWARE_CLASSES 的定義。大致的程式流程圖如下所示:

首先,Middleware都需要在 “project/settings.py” 中 MIDDLEWARE_CLASSES 的定義, 一個HTTP請求,將被這裡指定的中介軟體從頭到尾處理一遍,暫且稱這些需要挨個處理的中介軟體為處理鏈,如果鏈中某個處理器處理後沒有返回response,就把請求傳遞給下一個處理器;如果鏈中某個處理器返回了response,直接跳出處理鏈由response中介軟體處理後返回給用戶端,可以稱之為短路處理。 二、 中介軟體中的方法

Django處理一個Request的過程是首先通過中介軟體,然後再通過預設的URL方式進行的。我們可以在Middleware這個地方把所有Request攔截住,用我們自己的方式完成處理以後直接返回Response。因此瞭解中介軟體的構成是非常必要的。 Initializer: __init__(self)

出於效能的考慮,每個已啟用的中介軟體在每個伺服器處理序中只初始化一次。也就是說 __init__() 僅在服務進程啟動的時候調用,而在針對單個request處理時並不執行。

對一個middleware而言,定義 __init__() 方法的通常原因是檢查自身的必要性。如果 __init__() 拋出異常 django.core.exceptions.MiddlewareNotUsed ,則Django將從middleware棧中移出該middleware。

在中介軟體中定義 __init__() 方法時,除了標準的 self 參數之外,不應定義任何其它參數。 Request預先處理函數: process_request(self, request)

這個方法的調用時機在Django接收到request之後,但仍未解析URL以確定應當啟動並執行view之前。Django向它傳入相應的 HttpRequest 對象,以便在方法中修改。

process_request() 應當返回 None 或 HttpResponse 對象.

如果返回 None , Django將繼續處理這個request,執行後續的中介軟體, 然後調用相應的view.

如果返回 HttpResponse 對象,Django 將不再執行任何其它的中介軟體(無視其種類)以及相應的view。 Django將立即返回該 HttpResponse . View預先處理函數: process_view(self, request, callback, callback_args, callback_kwargs)

這個方法的調用時機在Django執行完request預先處理函數並確定待執行的view之後,但在view函數實際執行之前。

request

HttpRequest 對象。

callback

Django將調用的處理request的python函數. 這是實際的函數對象本身, 而不是字串表述的函數名。

args

將傳入view的位置參數列表,但不包括 request 參數(它通常是傳入view的第一個參數)
kwargs

將傳入view的關鍵字參數字典.

如同 process_request() , process_view() 應當返回 None 或 HttpResponse 對象。

如果返回 None , Django將繼續處理這個 request ,執行後續的中介軟體, 然後調用相應的view

如果返回 HttpResponse 對象,Django 將不再執行 任何 其它的中介軟體(不論種類)以及相應的view。Django將立即返回 Response後處理函數: process_response(self, request, response)

這個方法的調用時機在Django執行view函數並產生response之後。

該處理器能修改response的內容;一個常見的用途是內容壓縮,如gzip所請求的HTML頁面。

這個方法的參數相當直觀: request 是request對象,而 response 則是從view中返回的response對象。

process_response() 必須 返回 HttpResponse 對象. 這個response對象可以是傳入函數的那一個原始對象(通常已被修改),也可以是全新產生的。 Exception後處理函數: process_exception(self, request, exception)

這個方法只有在request處理過程中出了問題並且view函數拋出了一個未捕獲的異常時才會被調用。這個鉤子可以用來發送錯誤通知,將現場相關資訊輸出到記錄檔, 或者甚至嘗試從錯誤中自動回復。

這個函數的參數除了一貫的 request 對象之外,還包括view函數拋出的實際的異常對象 exception 。

process_exception() 應當返回 None 或 HttpResponse 對象.

如果返回 None , Django將用架構內建的異常處理機制繼續處理相應request。

如果返回 HttpResponse 對象, Django 將使用該response對象,而短路架構內建的異常處理機制

以下幾章會詳細介紹該機制。 三、 Django目錄結構

conf

主要有兩個作用:1) 處理全域配置, 比如資料庫、載入的應用、 MiddleWare等 2) 處理urls配置, 就是url與view的映射關係。

contrib (貢獻)

由Django的開發人員貢獻的功能模組,不過既然都已經隨版本發布, 就表示是官方的。

core

Django的核心處理庫,包括url分析、處理請求、緩衝等,其中處理請求是核心了,比如處理fastcgi就是由wsgi.py處理。

db

顧名思義,處理與資料庫相關的,就是ORM。

dispatch (指派,派遣)

其實這不是Django原創,是pydispatch庫,主要處 理消費者-工作者模式。

forms && newforms && oldforms

處理html的表單,不用多介紹。

middleware

中介軟體,就是處理HTTP的request和response的,類似外掛程式。比 如預設的common中介軟體的一個功能:當一個頁面沒有找對對應的 pattern時, 會自定加上‘/’重新處理。比如訪問/blog時,而定義的pattern是‘^blog/$’, 所以找不到對應的pattern,會自動再用/blog/尋找,當然前提是 APPEND_SLASH=True。

template

Django的模板

templatetags

處理Application的tag的wrapper,就是將INSTALLED_APPS中 所有的templatetags目錄添加到 django.templatetags目錄中,則當使用 {{load blog}}記載tag時,就可以使用 import django.templatetags.blog 方式載入了。不過這有一個問題,如果其他Application目錄中也有blog.py, 這會載入第一個出現blog.py的tag。其實在 Django中,有許多需要處理重名 的地方,比如template,需要格外小心,這個後續在介紹。

utils

公用庫,很多公用的類都在放在這裡。

views

最基本的view方法。 四、 Django 術語

在應用 Django 的時候,我們經常聽到一些術語:

Project

指一個完整的Web服務,一般由多個模組組成。

Application

可以理解為模組,比如使用者管理、部落格管理等,包含了資料的組成和資料的顯示,Applicaiton都需要在 “project/settings.py” 中 INSTALLED_APPS 的定義。

Middleware

就是處理request和response的外掛程式, Middleware都需要在 “project/settings.py” 中 MIDDLEWARE_CLASSES 的定義。

Loader

模板載入器, 其實就是為了讀取 Template 檔案的類,預設的有通過檔案系統載入和在 “Application/templates” 目錄中載入,Loader都需要在 “project/settings.py” 中 TEMPLATE_LOADERS 的定義。 五、 處理流程

其實和其他Web架構一樣,HTTP處理的流程大致相同,

Django處理一個Request的過程是首先通過中介軟體,然後再通過預設的URL方式進行的。我們可以在Middleware這個地方把所有Request攔截住,用我們自己的方式完成處理以後直接返回Response。

1. 載入配置

Django的配置都在 “Project/settings.py” 中定義,可以是Django的配置,也 可以是自訂的配置,並且都通過 django.conf.settings 訪問,非常方便。

2. 啟動

最核心動作的是通過 django.core.management.commands.runfcgi 的 Command 來啟動,它運行 django.core.servers.fastcgi 中的 runfastcgi , runfastcgi 使用了 flup 的 WSGIServer 來啟動 fastcgi 。而 WSGIServer 中攜帶了 django.core.handlers.wsgi 的 WSGIHandler 類的一個執行個體,通過 WSGIHandler來處理由Web伺服器(比如Apache,Lighttpd等)傳過來的請求,此 時才是真正進入Django的世界。

3. 處理 Request

當有HTTP請求來時, WSGIHandler 就開始工作了,它從 BaseHandler 繼承而來。 WSGIHandler 為每個請求建立一個 WSGIRequest 執行個體,而 WSGIRequest 是從 http.HttpRequest 繼承而來。接下來就開始建立 Response 了.

4. 建立Response

BaseHandler 的 get_response 方法就是根據 request 建立 response , 而 具體產生 response 的動作就是執行 urls.py 中對應的view函數了,這也是 Django可以處理“友好URL”的關鍵步驟,每個這樣的函數都要返回一個 Response 執行個體。此時一般的做法是通過 loader 載入 template 並產生頁面內 容,其中重要的就是通過 ORM 技術從資料庫中取出資料,並渲染到 Template 中,從而產生具體的頁面了

5. 處理Response

Django 返回 Response 給 flup , flup 就取出 Response 的內容返回給 Web 服務器,由後者返回給瀏覽器。

總之, Django 在 fastcgi 中主要做了兩件事:處理 Request 和建立 Response , 而它們對應的核心就是“urls分析”、“模板技術”和“ORM技術”

,一個HTTP請求,首先被轉化成一個HttpRequest對象,然後該對象被傳遞給Request中介軟體處理,如果該中介軟體返回了Response,則直接傳遞給Response中介軟體做收尾處理。否則的話Request中介軟體將訪問URL配置,確定哪個view來處理,在確定了哪個view要執行,但是還沒有執行該view的時候,系統會把request傳遞給View中介軟體處理器進行處理,如果該中介軟體返回了Response,那麼該Response直接被傳遞給Response中介軟體進行後續處理,否則將執行確定的View函數處理並返回Response,在這個過程中如果引發了異常並拋出,會被Exception中介軟體處理器進行處理。 六、 詳細全流程 一個 Request 到達了!

首先發生的是一些和 Django有關(前期準備)的其他事情,分別是:

1. 如果是 Apache/mod_python 提供服務,request 由 mod_python 建立的 django.core.handlers.modpython.ModPythonHandler 執行個體傳遞給 Django。

2. 如果是其他伺服器,則必須相容 WSGI,這樣,伺服器將建立一個 django.core.handlers.wsgi.WsgiHandler 執行個體。

這兩個類都繼承自 django.core.handlers.base.BaseHandler,它包含對任何類 型的 request 來說都需要的公用代碼。 有一個處理器(Handler)了

當上面其中一個處理器執行個體化後,緊接著發生了一系列的事情:

1. 這個處理器(handler)匯入你的 Django 設定檔。

2. 這個處理器匯入 Django 的自訂異常類。

3. 這個處理器調用它自己的 load_middleware 方法,載入所有列在 MIDDLEWARE_CLASSES中的 middleware 類並且內省它們。

最後一條有點複雜,我們仔細瞧瞧。

一 個 middleware 類可以滲入處理過程的四個階段:request,view,response 和 exception。要做到這一點,只需要定義指定的、恰當的方 法:process_request,process_view, process_response 和 process_exception。middleware 可以定義其中任何一個或所有這些方法,這取 決於你想要它提供什麼樣的功能。

當處理器內省 middleware 時,它尋找上述名字的方法,並建立四個列表作為處理器的執行個體變數:

1. _request_middleware 是一個儲存 process_request 方法的列表(在每一 種情況下,它們是真正的方法,可以直接調用),這些方法來自於任一個定 義了它們的 middleware 類。

1. _view_middleware 是一個儲存 process_view 方法的列表,這些方法來自 於任一個定義了它們的 middleware 類。

2. _response_middleware 是一個儲存 process_response 方法的列表,這些 方法來自於任一個定義了它們的 middleware 類。

3. _exception_middleware 是一個儲存 process_exception 方法的列表,這 些方法來自於任一個定義了它們的 middleware 類。 綠燈:現在開始

現在處理器已經準備好真正開始處理了,因此它給發送器發送一個訊號 request_started(Django 內部的發送器允許各種不同的組件聲明它們正在幹 什麼,並可以寫一些代碼監聽特定的事件。關於這一點目前還沒有官方的文檔, 但在 wiki上有一些注釋。)。接下來它執行個體化一個django.http.HttpRequest 的子類。根據不同的處理器,可能是 django.core.handlers.modpython.ModPythonRequest 的一個執行個體,也可能是 django.core.handlers.wsgi.WSGIRequest 的一個執行個體。需要兩個不同的類是因 為 mod_python 和 WSGI APIs 以不同的格式傳入 request 資訊,這個資訊需要 解析為 Django 能夠處理的一個單獨的標準格式。

一旦一個 HttpRequest 或者類似的東西存在了,處理器就調用它自己的 get_response 方法,傳入這個 HttpRequest 作為唯一的參數。這裡就是幾乎所 有真正的活動發生的地方。 Middleware,第一回合

get_response 做的第一件事就是遍曆處理器的 _request_middleware 執行個體變數 並調用其中的每一個方法,傳入 HttpRequest 的執行個體作為參數。

for middleware_method in self._request_middleware:

response = middleware_method(request)

if response:

break

這些方法可以選 擇短路剩下的處理並立即讓 get_response 返回,通過返回自身的一個值(如果 它們這樣做,傳回值必須是 django.http.HttpResponse 的一個執行個體,後面會討 論到)。如果其中之一這樣做了,我們會立即回到主處理器代碼,get_response 不會等著看其它 middleware 類想要做什麼,它直接返回,然後處理器進入 response 階段。

然而,更一般的情況是,這裡應用的 middleware 方法簡單地做一些處理並決定 是否增加,刪除或補充 request 的屬性。 關於解析

假設沒有一個作用於 request 的 middleware 直接返回 response,處理器下一 步會嘗試解析請求的 URL。它在設定檔中尋找一個叫做 ROOT_URLCONF 的配 置,用這個配置加上根 URL /,作為參數來建立 django.core.urlresolvers.RegexURLResolver 的一個執行個體,然後調用它的 resolve 方法來解析請求的 URL 路徑。

URL resolver 遵循一個相當簡單的模式。對於在 URL 設定檔中根據 ROOT_URLCONF 的配置產生的每一個在 urlpatterns 列表中的條目,它會檢查請 求的 URL 路徑是否與這個條目的Regex相匹配,如果是的話,有兩種選擇:

1. 如果這個條目有一個可以調用的 include,resolver 截取匹配的 URL,轉 到 include 指定的 URL 設定檔並開始遍曆其中 urlpatterns 列表中的 每一個條目。根據你 URL 的深度和模組性,這可能重複好幾次。

2. 否則,resolver 返回三個條目:匹配的條目指定的 view function;一個 從 URL 得到的未命名匹配組(被用來作為 view 的位置參數);一個關鍵 字參數字典,它由從 URL 得到的任意命名匹配組和從 URLConf 中得到的任 意其它關鍵字參數組合而成。

注意這一過程會在匹配到第一個指定了 view 的條目時停止,因此最好讓你的 URL 配置從複雜的正則過渡到簡單的正則,這樣能確保 resolver 不會首先匹配 到簡單的那一個而返回錯誤的 view function。

如果沒有找到匹配的條目,resolver 會產生 django.core.urlresolvers.Resolver404 異常,它是 django.http.Http404 例 外的子類。後面我們會知道它是如何處理的。 Middleware,第二回合

一旦知道了所需的 view function 和相關的參數,處理器就會查看它的 _view_middleware 列表,並調用其中的方法,傳入 HttpRequst,view function,針對這個 view 的位置參數列表和關鍵字參數字典。

# Apply view middleware

for middleware_method in self._view_middleware:

response = middleware_method(request, callback, callback_args, callback_kwargs)

if response:

break

還有,middleware 有可能介入這一階段並強迫處理器立即返回。 進入 View

如果處理過程這時候還在繼續的話,處理器會調用 view function。Django 中的 Views 不很嚴格因為它只需要滿足幾個條件:

2 必須可以被調用。

2 必須接受 django.http.HttpRequest 的執行個體作為第一位值參數。

2 必須能產生一個異常或返回 django.http.HttpResponse 的一個執行個體。

除了這些,你就可以天馬行空了。儘管如此,一般來說,views 會使用 Django 的 database API 來建立,檢索,更新和刪除資料庫的某些東西,還會載入並渲 染一個模板來呈現一些東西給終端使用者。 模板

Django 的模板系統有兩個部分:一部分是給設計師使用的混入少量其它東西的 HTML,另一部分是給程式員使用純 Python。

從一個 HTML 作者的角度,Django 的模板系統非常簡單,需要知道的僅有三個結構:

2 變數引用。在模板中是這樣: {{ foo }}。

2 模板過濾。在上面的例子中使用過濾豎線是這樣:{{ foo|bar }}。通常這 用來格式化輸出(比如:運行 Textile,格式化日期等等)。

2 模板標籤。是這樣:{% baz %}。這是模板的“邏輯”實現的地方,你可以 {% if foo %},{% for bar in foo %},等等,if 和 for 都是模板標籤。

變數引用以一種非常簡單的方式工作。如果你只是要列印變數,只要 {{ foo }},模板系統就會輸出它。這裡唯一的複雜情況是 {{ foo.bar }},這時模板系 統按順序嘗試幾件事:

1. 首先它嘗試一個字典方式的尋找,看看 foo[‘bar’] 是否存在。如果存在, 則它的值被輸出,這個過程也隨之結束。

2. 如果字典尋找失敗,模板系統嘗試屬性尋找,看看 foo.bar 是否存在。同 時它還檢查這個屬性是否可以被調用,如果可以,調用之。

3. 如果屬性尋找失敗,模板系統嘗試把它作為清單索引進行尋找。

如果所有這些都失敗了,模板系統輸出配置 TEMPLATE_STRING_IF_INVALID 的值,預設是Null 字元串。

模板過濾就是簡單的 Python functions,它接受一個值和一個參數,返回一個新的值。比如,date 過濾用一個 Python datetime 對象作為它的值,一個標準的 strftime 格式化字串作為它的參數,返回對 datetime 對象應用了格式化字元 串之後的結果。

模板標籤用在事情有一點點複雜的地方,它是你瞭解 Django 的模板系統是如何 真正工作的地方。 Django 模板的結構

在內部,一個 Django 模板體現為一個 “nodes” 集合,它們都是從基本的 django.template.Node 類繼承而來。Nodes 可以做各種處理,但有一個共同點: 每一個 Node 必須有一個叫做 render 的方法,它接受的第二個參數(第一個參 數,顯然是 Node 執行個體)是 django.template.Context 的一個執行個體,這是一個類 似於字典的對象,包含所有模板可以獲得的變數。Node 的 render 方法必須返回 一個字串,但如果 Node 的工作不是輸出(比如,它是要通過增加,刪除或修 改傳入的 Context 執行個體變數中的變數來修改模板上下文),可以返回Null 字元串。

Django 包含許多 Node 的子類來提供有用的功能。比如,每個內建的模板標籤都 被一個 Node 的子類處理(比如,IfNode 實現了 if 標籤,ForNode 實現了 for 標籤,等等)。所有內建標籤可以在 django.template.defaulttags 找到。

實際上,上面介紹的所有模板結構都是某種形式的 Nodes,純文字也不異常。變 量尋找由 VariableNode 處理,出於自然,過濾也應用在 VariableNode 上,標 簽是各種類型的 Nodes,純文字是一個 TextNode。

一般來說,一個 view 渲染一個模板要經過下面的步驟,依次是:

1. 載入需要渲染的模板。這是由 django.template.loader.get_template 完 成的,它能利用這許多方法中的任意一個來定位需要的模板檔案。 get_template 函數返回一個 django.template.Template 執行個體,其中包含 經過解析的模板和用到的方法。

2. 執行個體化一個 Context 用來渲染模板。如果用的是 Context 的子類 django.template.RequestContext,那麼附帶的上下文處理函數就會自動添 加在 view 中沒有定義的變數。Context 的構建器方法用一個鍵/值對的字 典(對於模板,它將變為名/值變數)作為它唯一的參數,RequestContext 則用 HttpRequest 的一個執行個體和一個字典。

3. 調用 Template 執行個體的 render 方法,Context 對象作為第一個位置參數。

Template 的 render 方法的傳回值是一個字串,它由 Template 中所有 Nodes 的 render 方法返回的值串連而成,調用順序為它們出現在 Template 中 的順序。 關於 Response,一點點

一旦一個模板完成渲染,或者產生了其它某些合適的輸出,view 就會負責產生一 個 django.http.HttpResponse 執行個體,它的構建器接受兩個可選的參數:

1. 一個作為 response 主體的字串(它應該是第一位置參數,或者是關鍵字 參數 content)。大部分時間,這將作為渲染一個模板的輸出,但不是必須 這樣,在這裡你可以傳入任何有效 Python 字串。

2. 作 為 response 的 Content-Type header 的值(它應該是第二位置參數, 或者是關鍵字參數 mine_type)。如果沒有提供這個參數,Django 將會使 用配置中 DEFAULT_MIME_TYPE 的值和 DEFAULT_CHARSET 的值,如果你沒有 在 Django 的全域設定檔中更改它們的話,分別是 “text/html” 和 “utf-8”。 Middleware,第三回合:異常

如果 view 函數,或者其中的什麼東西,發生了異常,那麼 get_response(我知 道我們已經花了些時間深入 views 和 templates,但是一旦 view 返回或產生異常,我們仍將重拾處理器中間的 get_response 方法)將遍曆它的 _exception_middleware 執行個體變數並調用那裡的每個方法,傳入 HttpResponse 和這個 exception 作為參數。如果順利,這些方法中的一個會執行個體化一個 HttpResponse 並返回它。 仍然沒有響應?

這時候有可能還是沒有得到一個 HttpResponse,這可能有幾個原因:

1. view 可能沒有傳回值。

2. view 可能產生了異常但沒有一個 middleware 能處理它。

3. 一個 middleware 方法試圖處理一個異常時自己又產生了一個新的異常。

這時候,get_response 會回到自己的異常處理機制中,它們有幾個層次:

1. 如果 exception 是 Http404 並且 DEBUG 設定為 True,get_response 將 執行 view django.views.debug.technical_404_response,傳入 HttpRequest 和 exception 作為參數。這個 view 會展示 URL resolver 試圖匹配的模式資訊。

2. 如果 DEBUG 是 False 並且異常是 Http404,get_response 會調用 URL resolver 的 resolve_404 方法。這個方法查看 URL 配置以判斷哪一個 view 被指定用來處理 404 錯誤。預設是 django.views.defaults.page_not_found,但可以在 URL 配置中給 handler404 變數賦值來更改。

3. 對於任何其它類型的異常,如果 DEBUG 設定為 True,get_response 將執 行 view django.views.debug.technical_500_response,傳入 HttpRequest 和 exception 作為參數。這個 view 提供了關於異常的詳細 資訊,包括 traceback,每一個層次 stack 中的本地變數,HttpRequest 對象的詳細描述和所有無效配置的列表。

4. 如果 DEBUG 是 False,get_response 會調用 URL resolver 的 resolve_500 方法,它和 resolve_404 方法非常相似,這時預設的 view 是 django.views.defaults.server_error,但可以在 URL 配置中給 handler500 變數賦值來更改。

此外,對於除了 django.http.Http404 或 Python 內建的 SystemExit 之外的任 何異常,處理器會給調度者發送訊號 got_request_exception,在返回之前,構 建一個關於異常的描述,把它發送給列在 Django 設定檔的 ADMINS 配置中的 每一個人。 Middleware,最後回合

現在,無論 get_response 在哪一個層次上發生錯誤,它都會返回一個 HttpResponse 執行個體,因此我們回到處理器的主要部分。一旦它獲得一個 HttpResponse 它做的第一件事就是遍曆它的 _response_middleware 執行個體變數並 應用那裡的方法,傳入 HttpRequest 和 HttpResponse 作為參數。

finally:

# Reset URLconf for this thread on the way out for complete

# isolation of request.urlconf

urlresolvers.set_urlconf(None)

try:

# Apply response middleware, regardless of the response

for middleware_method in self._response_middleware:

response = middleware_method(request, response)

response = self.apply_response_fixes(request, response)

注意對於任何想改變點什麼的 middleware 來說,這是它們的最後機會。 The check is in the mail

是該結束的時候了。一旦 middleware 完成了最後環節,處理器將給調度者發送 訊號 request_finished,對與想在當前的 request 中執行的任何東西來說,這 絕對是最後的調用。監聽這個訊號的處理者會清空並釋放任何使用中的資源。比 如,Django 的 request_finished 監聽者會關閉所有資料庫連接。

這件事發生以後,處理器會構建一個合適的傳回值送返給執行個體化它的任何東西 (現在,是一個恰當的 mod_python response 或者一個 WSGI 相容的 response,這取決於處理器)並返回。  

結束了,從開始到結束,這就是 Django 如何處理一個 request。

【轉】對Django架構架構和Request/Response處理流程的分析

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.