溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

圖解 Spring:HTTP 請求的處理流程與機(jī)制【2】

發(fā)布時間:2020-04-10 00:12:34 來源:網(wǎng)絡(luò) 閱讀:382 作者:IT老兵哥 欄目:軟件技術(shù)

2. HTTP 請求在 Web 容器中的處理流程

Web 容器以進(jìn)程的方式在計(jì)算機(jī)上運(yùn)行,我們知道進(jìn)程是系統(tǒng)資源分配的最小單元,線程是系統(tǒng)任務(wù)執(zhí)行的最小單元。從這個角度看,Web 容器就像是郵包收件人所居住的樓宇或小區(qū),HTTP 這套物流快遞體系只能將郵包投遞到樓宇前臺或者小區(qū)物業(yè)等處,而樓宇前臺或小區(qū)物業(yè)并不屬于物流快遞體系,就像 Web 容器并不屬于計(jì)算機(jī)網(wǎng)絡(luò)基礎(chǔ)設(shè)施一樣。之所以這樣分工,原因是網(wǎng)絡(luò)路由信息由域名服務(wù)器 DNS、路由器等設(shè)備掌握,Web 容器內(nèi)部體系結(jié)構(gòu)信息只有它自己知道。從 Web 容器接收到 HTTP 請求,到將其投送至特定的應(yīng)用,這期間還會經(jīng)歷一個復(fù)雜的過程,了解這個過程對于日常開發(fā)和問題分析都會有所幫助。接下來,老兵哥我將陪著你一起來剖析這個過程。

JAVA 語言領(lǐng)域的 Web 容器類型非常多,包括 Tomcat、Jetty、Resin、Websphere、Weblogic、JBoss、Glassfish、GonAS 等,其中 Tomcat 是由 Apache Software Foundation 維護(hù)的開源 Web 容器。Tomcat 市場占用率接近 60%,截止目前是最受歡迎的 Web 容器,如下圖所示橫跨 Web 服務(wù)器和 Java 應(yīng)用服務(wù)器。
圖解 Spring:HTTP 請求的處理流程與機(jī)制【2】
我們就以 Tomcat 為例來看看 Web 容器的內(nèi)部結(jié)構(gòu),作為符合 JAVA Servlet 標(biāo)準(zhǔn)規(guī)范的容器,Tomcat 是一款基于組件的 Java Web 應(yīng)用服務(wù)器,核心組件都是靈活可配的。Tomcat 最外層是 Catalina Servlet 容器,其他組件是按照特定格式要求配置在這個頂層容器當(dāng)中,配置文件就是安裝目錄下的:/conf/server.xml。通過這份配置文件,我們就可以了解 Tomcat 的體系結(jié)構(gòu),示例文件如下所示(快速瀏覽一遍,后面詳細(xì)剖析):

<Server port="8005" shutdown="SHUTDOWN">
  <Listener className="org.apache.catalina.startup.VersionLoggerListener" />
  <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
  <Listener className="org.apache.catalina.core.JasperListener" />
  <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
  <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />

  <GlobalNamingResources>
    <Resource name="UserDatabase" auth="Container"
              type="org.apache.catalina.UserDatabase"
              description="User database that can be updated and saved"
              factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
              pathname="conf/tomcat-users.xml" />
  </GlobalNamingResources>

  <Service name="Catalina">
    <Connector port="8080" protocol="HTTP/1.1" maxThreads=”150″ 
               connectionTimeout="20000"
               redirectPort="8443" />
    <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
    <Connector port=”8443″ maxThreads=”150″ minSpareThreads=”25″ 
               maxSpareThreads=”75″ enableLookups=”false” acceptCount=”100″ 
               debug=”0″ scheme=”https” secure=”true” 
               clientAuth=”false” sslProtocol=”TLS” />
    <Engine name="Catalina" defaultHost="localhost">
      <Realm className="org.apache.catalina.realm.LockOutRealm">
        <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
               resourceName="UserDatabase"/>
      </Realm>

      <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="localhost_access_log." suffix=".txt"
               pattern="%h %l %u %t "%r" %s %b" />
      </Host>
    </Engine>
  </Service>
</Server>

2.1 Tomcat 核心組件簡介

如果經(jīng)常使用配置 Tomcat,那么你對上述配置文件一定非常熟悉。為了方便大家理解,結(jié)合本文的主題,我們把上述這份配置文件中的關(guān)鍵節(jié)點(diǎn)提取出來,然后再逐一分析介紹:

<Server>                             ?
    <Service>
        <Connector />
        <Connector />
        <Engine>
            <Host>
                <Context />
            </Host>
        </Engine>        
    </Service>
</Server>

上述結(jié)構(gòu)中包含了 Tomcat 的核心組件:Server 組件在最頂層,代表整個 Tomcat 容器。一個 Server 組件中可以包含一個或多個 Service 組件。Service 在 Connector 和 Engine 外面包了一層,把它們組裝在一起對外提供服務(wù)。一個 Service 可以包含多個 Connector,但是只能包含一個 Engine。不同 Connector 負(fù)責(zé)接收不同端口上相應(yīng)協(xié)議的請求,而 Engine 負(fù)責(zé)處理請求。Engine 包含一個或多個 Host,Host 包含一個或多個 Context,Engine、Host、Context 都屬于容器組件,一個 Host 組件代表一個虛擬主機(jī),一個 Context 組件代表在隸屬 Host 上運(yùn)行的一個 Web 應(yīng)用。
圖解 Spring:HTTP 請求的處理流程與機(jī)制【2】

2.1.1 頂層類組件 Server

它是整個配置文件的唯一根元素,代表整個 Tomcat 容器,內(nèi)部可以包含多個 Service。Server 主要職責(zé)就是管理多個 Service,對外提供給客戶端訪問,同時維護(hù)所有 Service 的生命周期,包括初始化服務(wù)、結(jié)束服務(wù)、定位客戶端要訪問的 Service 等等。所有 Tomcat 組件的生命周期都是通過 Lifecycle 接口來控制的,組件只要繼承這個接口并實(shí)現(xiàn)其中的方法就可以統(tǒng)一被父組件控制了,這樣層層遞進(jìn) Server 組件就可以控制所有組件的生命周期了,而控制 Server 就是通過啟動和關(guān)停 Tomcat。在前面配置示例中,Server 的配置如下所示:

<Server port="8005" shutdown="SHUTDOWN">

其中,屬性 shutdown 指定關(guān)閉 Server 的指令。屬性 port 指定 Server 接收 shutdown 指令的端口號,設(shè)置為“-1”可以禁掉該端口。

2.1.2 頂層類組件 Service

Service 主要職責(zé)就是將 Engine 與 Connector 裝配在一起對外提供服務(wù),一個 Service 可以包含多個 Connector,但只能包含一個 Engine,其中 Connector 負(fù)責(zé)從客戶端接收請求,Engine 負(fù)責(zé)處理 Connector 接收進(jìn)來的請求。如前面配置示例中,Service 的配置如下所示:

<Service name="Catalina">

我們可以通過屬性 name 為 Service 指定名稱,不同的 Service 負(fù)責(zé)監(jiān)管其下屬 Connector 所綁定的端口。

2.1.3 連接器組件 Connector

Tomcat 的工作模式可以分為下面兩類:

  • 作為 Web 服務(wù)器:請求是直接來自于客戶端 HTTP 請求(或?yàn)g覽器)。
  • 作為 Java Web 應(yīng)用服務(wù)器:請求來自于前置 Web 服務(wù)器,通常包括:Apache、IIS、Nginx 等。Tomcat 主要優(yōu)勢是作為 JSP/Servlet 容器,在處理靜態(tài)資源方面效率偏低。因此,它通常要跟 Apache、IIS、Nginx 等 Web 服務(wù)器集成使用。AJP 協(xié)議主要負(fù)責(zé) Tomcat 和集成 Web 服務(wù)器的交互連接。
    圖解 Spring:HTTP 請求的處理流程與機(jī)制【2】
    每個 Service 可以有一個或多個 Connector,不同工作模式下,Tomcat 需要為各種類型的請求分別定義相應(yīng)的 Connector,這樣才能正確接收客戶端對應(yīng)協(xié)議的請求。定義 Connector 可以使用多種屬性,某些屬性只適用于某種特定的 Connector 類型。一般說來,常見的 Connector 有 4 種類型:HTTP、SSL、AJP、Proxy。
    圖解 Spring:HTTP 請求的處理流程與機(jī)制【2】
    作為通信接口,Connector 為其所屬特定的 Service 接收外部客戶端請求,以及回送應(yīng)答至外部客戶端。具體職責(zé)包括創(chuàng)建 Request、Response 對象用于跟外部客戶端交換數(shù)據(jù),并將 Request 交給配套的 Engine 來處理。通過修改 Connector 的屬性取值,我們可以控制 Service 所監(jiān)聽的網(wǎng)絡(luò)協(xié)議及端口號,具體示例如下:
<Connector port="8080" protocol="HTTP/1.1" maxThreads=”150″ 
           connectionTimeout="20000" 
           redirectPort="8443" />
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
<Connector port=”8443″ maxThreads=”150″ minSpareThreads=”25″ 
           maxSpareThreads=”75″ enableLookups=”false” acceptCount=”100″ 
           debug=”0″ scheme=”https” secure=”true” 
           clientAuth=”false” sslProtocol=”TLS” />
  • 配置一,客戶端可以通過 8080 端口號使用 HTTP 協(xié)議訪問 Tomcat。
  • 配置二,客戶端可以通過 8009 端口使用 AJP 協(xié)議訪問 Tomcat。AJP 協(xié)議主要用于跟其他的 HTTP 服務(wù)器連接協(xié)作。當(dāng) Tomcat 與其他 HTTP 服務(wù)器集成時,我們就要用到這個連接器。
  • 配置三,客戶端可以通過 8443 端口號使用 HTTPS 協(xié)議訪問 Tomcat。

連接器的定義可以配置的屬性非常多,下面是常用屬性的說明:

  • address:指定連接器監(jiān)聽的地址,默認(rèn)為所有地址,即:0.0.0.0。
  • maxThreads:支持最大的并發(fā)連接數(shù),默認(rèn)為:200。
  • port:監(jiān)聽端口,默認(rèn)為:0。
  • protocol:連接器使用的協(xié)議,默認(rèn)為:HTTP/1.1,定義 AJP 協(xié)議時通常為:AJP/1.3。
  • redirectPort:在強(qiáng)制要求 HTTPS 的情況下,如果請求時 HTTP,則將會被重定向至 8443 端口。
  • connectionTimeout:連接的超時時間,單位為毫秒,默認(rèn)為 60000,即 1 分鐘;
  • enableLookups:是否通過 request.getRemoteHost() 進(jìn)行 DNS 查詢以獲取客戶端的主機(jī)名。
  • acceptCount:設(shè)置等待隊(duì)列的最大長度。通常,在 Tomcat 所有處理線程均處于繁忙狀態(tài)時,新請求將被放置于等待隊(duì)列中。
2.1.4 容器類組件 Engine

Engine 內(nèi)部可以包含多個 Host,它是 Service 組件中負(fù)責(zé)請求處理的組件。它從一個或多個 Connector 中接收請求并處理,并將處理結(jié)果封裝成應(yīng)答交給 Connector,最終回傳給外部客戶端。在前文配置文件示例中,Engine 的配置如下所示:

<Engine name="Catalina" defaultHost="localhost">

其中,屬性 name 用于日志和錯誤信息,其取值在整個 Server 中保證唯一。屬性 defaultHost 指定了默認(rèn)的Host 名稱,當(dāng) HTTP 請求所指定的 Host 名稱不存在時,一律使用 defaultHost 指定的 Host 來處理。因此,defaultHost 的值,必須與 Engine 中的某個 Host 組件的屬性 name 取值匹配。

2.1.5 容器類組件 Host

Host 代表一個虛擬主機(jī),它對應(yīng)計(jì)算機(jī)網(wǎng)絡(luò)上的一個實(shí)體,即某個在 DNS 服務(wù)器上注冊過的域名或者 IP 地址,例如:www.abc.com 或 201.187.10.21。Host 內(nèi)部可以包含多個 Context,每個 Context 表示一個 Web 應(yīng)用。Host 負(fù)責(zé)安裝、展開、啟動和結(jié)束每個 Web 應(yīng)用。

客戶端在填寫收件人地址時會通過主機(jī)名來標(biāo)識它希望訪問的服務(wù)器,Tomcat 將從 HTTP 請求頭的 Host 字段提取主機(jī)名,然后再匹配對應(yīng)的虛擬主機(jī)。如果沒有找到匹配的,HTTP 請求將被發(fā)送至默認(rèn)主機(jī) defaultHost。因此,默認(rèn)主機(jī)不需要是在 DNS 服務(wù)器上注冊的網(wǎng)絡(luò)名,例如:localhost。在前面配置示例中,Host 的配置如下所示:

<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">

其中,屬性 name 指定虛擬主機(jī)的名稱。屬性 appBase 指定 Web 應(yīng)用所在的目錄,默認(rèn)值是 webapps,這是一個相對路徑,標(biāo)識 Tomcat 安裝根目錄下的 webapps 文件夾。屬性 unpackWARs 指定是否將 Web 應(yīng)用的 WAR 文件解壓。如果取值為 true,Tomcat 將以解壓后的文件結(jié)構(gòu)運(yùn)行該 Web 應(yīng)用;如果為 false,Tomcat 將直接使用 WAR 文件運(yùn)行 Web 應(yīng)用。屬性 autoDeploy 指定是否自動部署 Web 應(yīng)用。

2.1.6 容器類組件 Context

Context 代表在特定虛擬主機(jī)上運(yùn)行的一個 Web 應(yīng)用,負(fù)責(zé)處理某個特定 Web 應(yīng)用的所有請求。每個 Web 應(yīng)用要么基于 WAR 文件,要么基于 WAR 文件解壓后對應(yīng)的文件目錄。在前文配置文件示例中,我們沒有看到 Context 的配置,這是因?yàn)?Host 開啟了自動部署,Web 應(yīng)用沒有在配置文件中配置靜態(tài)部署,而是由 Tomcat 通過特定的規(guī)則自動部署,Context 組件也將被自動創(chuàng)建。Context 通過屬性 path 來唯一標(biāo)識自身??紤]到 Web 應(yīng)用自動部署與本文主題關(guān)系不大,老兵哥我就不再展開,如果你對此內(nèi)容感興趣,可以找資料做擴(kuò)展閱讀。

2.1.7 內(nèi)嵌類元素

除了前面介紹的核心組件外,Tomcat 還提供了 Listener、GlobalNamingResources、Realm、Valve 等組件,這些組件都是嵌入到核心組件當(dāng)中來使用,我們將它們歸為內(nèi)嵌組件,考慮到不涉及主題就不再贅述。

2.2 Tomcat 處理 HTTP 請求的流程

在前面各個章節(jié)介紹的各種核心組件基礎(chǔ)上,我們一起來看看,當(dāng) HTTP 請求被投遞到 Tomcat 所在主機(jī)之后,Tomcat 是如何將 HTTP 請求派發(fā)給特定的 Web 應(yīng)用來處理的:

  • 根據(jù)協(xié)議類型和端口號選定 Service 和 Engine:Service 下屬的 Connector 組件負(fù)責(zé)監(jiān)聽接收特定協(xié)議和特定端口的請求。因此,當(dāng) Tomcat 啟動時,Service 組件就開始監(jiān)聽特定的端口,如前文配置文件示例,Catalina 這個 Service 監(jiān)聽了 HTTP 協(xié)議 8080 端口和 AJP 協(xié)議的 8009 端口。當(dāng) HTTP 請求抵達(dá)主機(jī)網(wǎng)卡的特定端口之后,Tomcat 就會根據(jù)協(xié)議類型和端口號選定處理請求的 Service,隨即 Engine 也就確定了。通過在 Server 中配置多個 Service,可以實(shí)現(xiàn)通過不同端口訪問同一主機(jī)上的不同應(yīng)用。
  • 根據(jù)域名或 IP 地址選定 Host:待 Service 被選定之后,Tomcat 將在 Service 中尋找與 HTTP 請求頭中指定的域名或 IP 地址匹配的 Host 來處理該請求。如果沒有匹配成功,則采用 Engine 中配置的默認(rèn)虛擬主機(jī) defaultHost 來處理該請求。
  • 根據(jù) URI 選定 Context:URI 中的 context-path 指定了 HTTP 請求將要訪問的 Web 應(yīng)用。當(dāng)請求抵達(dá)時,Tomcat 將根據(jù) Context 的屬性 path 取值與 URI 中的 context-path 的匹配程度來選擇 Web 應(yīng)用處理相應(yīng)請求,例如:Web 應(yīng)用 spring-demo 的 path 屬性是”/spring-demo”,那么請求“/spring-demo/user/register”將交由 spring-demo 來處理。
    圖解 Spring:HTTP 請求的處理流程與機(jī)制【2】
    最終,我們還是繼續(xù)用向下文這個地址發(fā)送 HTTP 請求為例,將整個處理流程串一遍:

http://201.187.10.21:8080/spring-demo/user/register

  1. 客戶端(或?yàn)g覽器)發(fā)送請求至主機(jī)(201.187.10.21)的端口 8080,被在該端口上監(jiān)聽的 Coyote HTTP/1.1 Connector 所接收。
  2. Connector 將該請求交給它所在 Service 的 Engine 來負(fù)責(zé)處理,并等待 Engine 的回應(yīng)。
  3. Engine 獲得請求之后從報文頭中提取主機(jī)名稱(201.187.10.21),在所有虛擬主機(jī) Host 當(dāng)中尋找匹配。
  4. 在未匹配到同名虛擬主機(jī)的情況下,Engine 將該請求交給名為 localhost 的默認(rèn)虛擬主機(jī) Host 處理。
  5. Host 獲得請求之后將根據(jù) URI(/spring-demo/user/register)中的 context-path 的取值“/spring-demo” 去匹配它所擁有的所有 Context,將請求交給代表應(yīng)用 spring-demo 的 Context 來處理。
  6. Context 構(gòu)建 HttpServletRequest、HttpServletResponse 對象,將其作為參數(shù)調(diào)用應(yīng)用 spring-demo,由應(yīng)用完成業(yè)務(wù)邏輯執(zhí)行、結(jié)果數(shù)據(jù)存儲等過程,等待應(yīng)答數(shù)據(jù)。
  7. Context 接收到應(yīng)用返回的 HttpServletResponse 對象之后將其返回給 Host。
  8. Host 將 HttpServletResponse 對象返回給 Engine。
  9. Engine 將 HttpServletResponse 對象返回 Connector。
  10. Connector 將 HttpServletResponse 對象返回給客戶端(或?yàn)g覽器)。

2.3 Tomcat 體系結(jié)構(gòu)演進(jìn)的趨勢剖析

從上述體系結(jié)構(gòu)剖析來看,Tomcat 這款 Java Web 應(yīng)用服務(wù)器的功能還是非常強(qiáng)大的,它可以在一個實(shí)例進(jìn)程當(dāng)中同時支持多種協(xié)議,同時支持多個虛擬主機(jī),每個虛擬主機(jī)下還支持部署多款應(yīng)用,具備強(qiáng)大的擴(kuò)展性和靈活性。為什么它具備這樣一種體系結(jié)構(gòu)呢?這其實(shí)跟 Tomcat 誕生時的基礎(chǔ)架構(gòu)相匹配的,當(dāng)時服務(wù)器是以小型機(jī)或 PC 服務(wù)器為主,缺乏現(xiàn)在容器這種切分資源的虛擬技術(shù),進(jìn)程是系統(tǒng)資源分配的最小單元。為了更加充分地利用每臺計(jì)算機(jī)上的資源,我們通常要在同一臺計(jì)算機(jī)上部署多款應(yīng)用,但是在一臺計(jì)算機(jī)上運(yùn)行多個 Tomcat 實(shí)例所帶來的復(fù)雜度是非常高的,不如在同一個 Tomcat 實(shí)例中部署多款 Web 應(yīng)用,這樣在配置運(yùn)維等管理上面更加便利。

在這種架構(gòu)下,Tomcat 處理 HTTP 請求就需要經(jīng)過上述復(fù)雜的過程,這也再次印證老兵哥我堅(jiān)信的一個觀點(diǎn):不存在絕對好或壞的架構(gòu),匹配當(dāng)時業(yè)務(wù)場景的架構(gòu)就是好架構(gòu)!隨著互聯(lián)網(wǎng)業(yè)務(wù)的發(fā)展和云計(jì)算的興起,為了更好地管理大規(guī)模應(yīng)用集群,我們需要借助容器等虛擬化技術(shù)將大顆粒資源分割成更小的、標(biāo)準(zhǔn)的單元,每個容器中只安裝一個 Web 容器,每個 Web 容器中只部署一個應(yīng)用,在標(biāo)裝化下我們就可以采用云計(jì)算的自動化操作。

按照這個趨勢發(fā)展下去,Web 容器的架構(gòu)用不著這么復(fù)雜了,其價值也會不斷弱化。以前,Tomcat 都是需要單獨(dú)安裝的,應(yīng)用是后續(xù)再部署到 Tomcat 當(dāng)中的。但目前在 Spring Boot 的開發(fā)模式下,Tomcat 是以 Starter 方式作為內(nèi)嵌 Web 容器,它已經(jīng)不再需要獨(dú)立安裝部署了。在越來越標(biāo)裝化的趨勢下,Tomcat 基本上采用默認(rèn)配置,用戶基本上不用太關(guān)注它了。剖析了解它的原因,就是老兵哥我在開題中所說的:知其然,知其所以然。

這個演進(jìn)過程就像住宅樣式的變遷,古代城市人口密度沒有這么大,每家每戶都是獨(dú)門獨(dú)院的平房。隨著近代人口不斷涌入城市,早前住宅的空間利用率太低,無法支撐快速增長的居住需求,這時候高層樓房就應(yīng)運(yùn)而生了,每棟樓房都有多個樓層,每個樓層分割成多套房子,每套房子居住一戶家庭,Tomcat 的體系結(jié)構(gòu)就類似這種高層樓房。但現(xiàn)代城市的人口還在不斷增長,早前的高層樓房也無法滿足居住需求了,不夠標(biāo)準(zhǔn)化,缺乏物業(yè)管理,周邊配套不全,空間利用率還有待于提高,在這種情況下樓盤小區(qū)誕生了,標(biāo)準(zhǔn)化得到了提升,也配套了物業(yè)管理,這就類似云計(jì)算。

本文主要價值是幫助大家梳理出端到端的全流程框架,也就是我們常說的全局視角或者上帝視角。有了這個框架之后,我們可以根據(jù)自己的需要按圖索驥找相關(guān)節(jié)點(diǎn)的資料來研究學(xué)習(xí),不至于陷入細(xì)節(jié)找不到方向。當(dāng)然,考慮到我們每個人的工作學(xué)習(xí)情況不同,平時遇到的問題也不同,本文內(nèi)容無法覆蓋所有人遇到的問題,歡迎大家留言提問,也歡迎關(guān)注我的博客或公號“IT老兵哥”交流互動,我會盡力盡快解答大家提出的問題,謝謝!

本系列其他文章索引如下:

  • 圖解 Spring:HTTP 請求的處理流程與機(jī)制【1】
  • 圖解 Spring:HTTP 請求的處理流程與機(jī)制【3】
  • 圖解 Spring:HTTP 請求的處理流程與機(jī)制【4】
  • 圖解 Spring:HTTP 請求的處理流程與機(jī)制【5】
向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI