首頁  >  文章  >  web前端  >  網路技術和瀏覽器的演變

網路技術和瀏覽器的演變

DDD
DDD原創
2024-11-03 07:08:03417瀏覽

Evolution of Web Tech and Browsers

嘿,那裡!您是否想知道網路究竟是如何運作的,以及當您在神秘的瀏覽器中輸入 URL 時到底會發生什麼?別擔心,你並不孤單 ——我們大多數人都將網路視為某種黑盒子。但既然你已經點擊了這個博客,我猜你可能想看看裡面的情況。太棒了!好奇心可能害死貓,但對開發者來說,它是秘密武器。

即使您對它的工作原理有所了解,您仍然可能會質疑它為什麼會這樣演變。我相信「要了解現在並預測或影響未來,我們需要了解過去」。或者正如一些人建議的那樣,哼年表 samajhna chahiye!因此,讓我們回顧一下網頁技術和瀏覽器的演變,為了清楚起見,將其分為四個簡化的階段。在本次旅程結束時,您不僅會了解網路技術是如何演變的,還會了解幕後發生的事情、這些變化發生的原因以及它們對網路的未來意味著什麼。

注意:這些不是確切的時間表,而是幫助理解的簡化階段。

第零階段:史前網絡

讓我們回到20世紀80年代之前

想像一群研究人員在美國的大學裡忙碌,在電腦之間鋪設實體線路來傳輸或共享資料。這些技術先驅建立了 FTP(文件傳輸協定)和 SMTP(簡單郵件傳輸協定)等協定來共享文件和發送電子郵件 ——主要是關於他們的開創性實驗,也許還有偶爾的辦公室八卦。曾經有一些伺服器,我們可以透過遠端客戶端連接到伺服器,並使用書面命令在磁碟上儲存或取得檔案。

這對於少量資料很有用,但隨著資料成長得越來越快,尋找特定資訊變得非常頭痛。檢索資料需要知道確切的路徑、伺服器位址,也許還需要做一點舞蹈來安撫電腦之神。有價值的資訊有可能在數位洗牌中遺失,分散在伺服器上,就像襪子消失在洗衣漩渦中一樣。

第一階段:網路的誕生

進入 20 世紀 80 年代末和 90 年代初

出現了一位才華洋溢的英國人,名叫提姆·伯納斯·李爵士。他撰寫了一份名為資訊管理:提案的提案。他在其中談到了使用被稱為“超文本”的非線性文字系統,這意味著文字包含指向相關資訊的鏈接,就像一個巨大的蜘蛛網一樣連接起來。因此,透過相關數據進行導航和探索變得更加容易,並且資訊遺失也將最小化!

在這個提案中,他也將互連的電腦稱為「網路」。就這樣,萬維網誕生了!他並沒有就此止步。他繼續發明了超文本傳輸協定(HTTP),開發了第一個瀏覽器(名為WorldWideWeb(後來更名為Nexus))、第一個HTTP Web伺服器和第一個網站。談超越成就!

  • HTTP(超文本傳輸協定):一組用於在客戶端(例如,您的Web 瀏覽器)和Web 伺服器(Web 伺服器)之間傳輸資訊的規則、語法和語義。託管網站的遠端電腦)。如果您想知道這個名稱,最初它只是用於傳輸 HTML 檔案。但在引入標頭(尤其是 Content-Type 標頭)後,它在後續版本中演變為支援所有類型資料的傳輸。

  • HTTP Web 伺服器 :可以理解此 HTTP 協定的電腦。它的主要工作是解析請求並提供請求的回應,此時主要是靜態 HTML、CSS、JPG 檔案。

此時HTML(超文本標記語言)開始發揮作用,它將超文本的想法與SGML(標準通用標記語言)結合,然後用於格式化文件。 HTML 的第一個版本非常基礎——它支援標題、段落、清單和連結。沒有花俏的字體或華麗的動畫 — 只有必需品。

在最初的幾年裡,人脈就像研究人員和學者的專屬俱樂部。然後一些聰明的人開發了一個名為Mosaic的瀏覽器,它可以顯示圖像。是的,圖像!這使得網路更容易被大眾所訪問,因為,讓我們面對現實吧,一張圖片勝過一千行(不過這個部落格中沒有圖片?)!

在瀏覽器的引擎蓋下

那麼,讓我們看看這些具有上述功能的瀏覽器內部發生了什麼

使用者介面:每個瀏覽器的頂部都有一個導覽欄,所有開啟的標籤(或當時的視窗)都可見。下面是地址欄,您可以在其中輸入網站地址。下面是顯示您輸入的網站內容的地方(視窗)。請記住,這是在搜尋引擎出現之前,所以如果您不知道確切的地址,那麼您就不走運了 — 有點像試圖找到一個沒有 GPS 或地圖的地方。

取得資料:當您輸入網站位址時,瀏覽器的網路模組將透過執行 DNS 解析等任務來取得數據,並與伺服器建立安全連線以開始通訊。然後瀏覽器會從伺服器接收 HTML 形式的資料。

渲染引擎 :渲染引擎​​將開始解析 HTML。如果它遇到需要額外資源的標籤,例如圖像 (網路技術和瀏覽器的演變) 或樣式 (

然後它會從 HTML 建立一個文件物件模型 (DOM) 樹,其中每個標籤成為樹中的一個節點。在取得並解析 CSS 後,它將建立 CSS 物件模型 (CSSOM)。這兩個模型組合起來創建渲染樹,它將用於確定要顯示的內容以及如何顯示它。

  • 佈局和繪畫:接下來是佈局階段,渲染引擎計算頁面上每個元素的大小和位置。從相對於視窗(網頁的可見區域)的標籤開始,它將在渲染樹中工作。最後,在繪製階段,渲染引擎與相應作業系統的渲染 API 進行通信,以繪製螢幕上的所有內容。

生活在限制中

到此階段結束時,使用者可以查看靜態網站並瀏覽頁面。表單允許基本的使用者交互,例如輸入文字和單擊按鈕,並且此表單資料通常會透過電子郵件傳輸給開發人員。但問題是:無法根據使用者互動動態更改內容。用戶只能點擊並在提供的連結之間導航。

需要更新一些東西嗎?再次從伺服器取得整個新的 HTML。想要為不同的使用者顯示不同的內容?抱歉,沒有發生。你不能加入任何程式邏輯——沒有循環,沒有條件,什麼都沒有。如果您想要在多個頁面上使用導覽選單,則必須在各處複製並貼上相同的程式碼。

第二階段:伺服器端腳本的興起

現在讓我們快轉到 20 世紀 90 年代中後期

開發人員開始思考,「如果我們可以將程式語言與 HTML 混合起來添加一些邏輯,讓我們的生活更輕鬆,會怎麼樣?」這導致了伺服器端腳本的出現。 Java、PHP 和 Python 等語言被嵌入到 HTML 中,讓開發人員編寫可以動態處理資料、做出決策和產生 HTML 的程式碼。伺服器現在可以為每個使用者自訂內容,而不是提供靜態 HTML 檔案。

這如何改變事情?

從瀏覽器的角度:瀏覽器仍然取得並呈現 HTML,但它收到的內容更動態。表單變得更加強大,能夠使用 POST 請求將資料傳送到伺服器端點。

  • 快取和 Cookie:瀏覽器上的快取變得更加複雜。他們在本地儲存圖像和樣式表等資源,從而減少了重複獲取它們的需要。引入 Cookie 是為了透過無狀態 HTTP 協定維護狀態。它們允許伺服器在客戶端儲存小塊數據,這些數據與後續請求一起發回。這對於維護會話、使用者首選項、保持使用者登入 等操作至關重要,這樣您就不必每次眨眼時都輸入密碼。

在伺服器端:伺服器變得更加繁忙。在此之前,我們只有 Web 伺服器,用於提供靜態檔案。但此時,又引入了一些東西,例如應用程式伺服器、資料庫伺服器(可以儲存使用者資料、產品目錄等)等。它們現在處理可以處理使用者輸入、與資料庫互動並產生自訂 HTML 的腳本。這是電子商務開始蓬勃發展的時代。 Amazon 和 eBay 等公司可以根據使用者搜尋、偏好和行為動態顯示產品。

  • 應用程式伺服器:Web 伺服器本質上無法運行任何腳本,因此為了完成這項工作引入了應用程式伺服器。基本上,應用程式伺服器位於 Web 伺服器後面。每當有請求到來時,Web Server會根據設定檢查是否需要到Application Server,並將請求傳送到Application Server。然後,應用程式伺服器處理請求、執行腳本並產生 HTML 文件,然後將其傳輸到 Web 伺服器來為客戶端提供服務。因此,Web 伺服器的作用類似於應用程式伺服器的反向代理。

JSP(JavaServer Pages)範例

在我的大學時代,我記得修補一個舊的 JSP 計畫。這些腳本通常遵循一個通用的結構:它們由 HTML 組成,並且在需要添加邏輯的地方,使用特殊標識符嵌入,例如 。 (關閉)在 JSP 的情況下。這是一個簡單的例子:

greet.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
    <title>Greeting Page</title>
</head>
<body>
    <h1>Greeting:</h1>
    <p>
        Hello, <%= request.getParameter("name") != null ? request.getParameter("name") : "Guest" %>!
    </p>
</body>
</html>

在此範例中,當使用者提交姓名時,伺服器會接收包含表單資料的 HTTP 請求,處理訊息,並動態為使用者產生個人化問候語。不再有通用的「你好,世界!」現在是「你好,[你的名字]!」 — 即時自我提升。

動態內容產生:您可以從資料庫中取得資料並循環存取它或使用它來產生 HTML 元素,而不是硬編碼清單或內容。例如,顯示水果清單:

<%
    String[] fruits = {"Apple", "Banana", "Cherry", "Mango"};
%>

<ul>
    <% for(int i = 0; i < fruits.length; i++) { %>
        <li><%= fruits[i] %></li>
    <% } %>
</ul>

這可以輕鬆擴展到從資料庫中獲取水果,使您的內容更加動態和新鮮!

新的挑戰

雖然伺服器端腳本改變了遊戲規則,但它也面臨挑戰。

整頁刷新 :每次與伺服器互動時,例如提交表單或點擊鏈接,整個頁面都必須重新加載,因為任何邏輯只能在應用程式伺服器上執行,這會生成新的HTML。用戶必須等待伺服器回應才能看到其操作的結果。這導致了不太好的用戶體驗。

伺服器負載:伺服器必須處理所有處理,從執行腳本到查詢資料庫。隨著網站變得越來越流行,伺服器在負載增加的情況下陷入困境,導致用戶的載入時間增加和延遲。我們知道耐心是一種美德,但使用者卻不具備這種美德。隨著瀏覽器和客戶端電腦的能力越來越強,這就提出了一個問題:為什麼它們不能承擔一些工作負載來提高效能和回應能力?

第三階段:客戶端革命

進入了開發人員厭倦了全頁重新載入的時代。是時候做出改變了,而這種改變以客戶端腳本或客戶端渲染 (CSR) 的形式出現。

JavaScript 早在 1995 年就由 Netscape 悄悄推出,現在開始成為人們關注的焦點。它使開發人員能夠直接在使用者的瀏覽器中執行程式碼,這意味著並非每次互動都必須涉及伺服器。這帶來了更流暢、更能回應的網路體驗。這場革命涉及幾個主要因素:

增強的瀏覽器功能:隨著時間的推移,使用者裝置變得越來越強大 — 瀏覽器也是如此。因此,將一些工作從伺服器轉移到瀏覽器變得顯而易見,這極大地改善了用戶體驗。瀏覽器不再只是被動的文檔檢視者;它們演變成能夠運行複雜應用程式的平台。

Web API:為了利用這種新發現的力量,瀏覽器開始提供 Web API ——一組允許 JavaScript 與瀏覽器功能互動的函數。幫助 JavaScript 發展的幾個主要 Web API 是:

  • DOM API 提供了一種在瀏覽器中動態互動和操作網頁結構和內容的方法。它還允許在任何元素上新增事件偵聽器,例如單擊、滑鼠移動等,使開發人員能夠立即回應使用者互動。想要在使用者點擊按鈕時新增段落嗎?不要再次產生整個 HTML,這很簡單。
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
    <title>Greeting Page</title>
</head>
<body>
    <h1>Greeting:</h1>
    <p>
        Hello, <%= request.getParameter("name") != null ? request.getParameter("name") : "Guest" %>!
    </p>
</body>
</html>
  • XMLHttpRequest 改變了遊戲規則。它使開發人員能夠直接從瀏覽器中運行的程式碼發出非阻塞非同步 HTTP 請求,並從伺服器取得資料。過去,資料通常以 XML 格式傳輸——「因此得名」——但後來 JSON 取代了它,因為它更簡潔且更易於使用。最終,fetch API 出現了,提供了進階功能和更簡潔的語法。

AJAX(非同步 JavaScript 和 XML):AJAX 是這場革命背後的關鍵技術之一。它解釋了網頁如何與後台伺服器通訊以獲取所需資料並使用 DOM API 和 XMLHttpRequest 直接在瀏覽器中更新內容,而無需重新載入整頁。突然間,網路開始變得…互動!這個名字同樣來自 XML,用於資料傳輸。

這如何改變事情?

從瀏覽器的角度來看:一個新的<script> HTML 中引入了 tag,允許開發者直接在 HTML 中加入 JavaScript 程式碼。當瀏覽器的渲染引擎解析 HTML 並遇到 <script> 時,標籤,它將獲取並執行腳本(順序取決於 async 和 defer 屬性),允許動態內容和互動功能。 </script>

  • JavaScript 引擎: 為了評估這些腳本,瀏覽器中引入了 JavaScript 引擎。早期的引擎相對簡單且速度較慢,但 Google 的 V8 和 Mozilla 的 SpiderMonkey 等現代引擎已經有了顯著的發展,允許更複雜的客戶端邏輯。

  • 事件循環: JavaScript 被設計為單線程腳本語言,以保持語言的簡單和輕量級。這種設計選擇也受到運算資源有限且維持 DOM(文件物件模型) 執行緒安全、防止操作 DOM 時的競爭條件等因素的影響。

    由於所有腳本執行和渲染任務共享一個線程,JavaScript 需要一種在不阻塞主線程的情況下處理非同步操作的方法。為了實現這一點,JavaScript 依賴 事件循環.

    的概念

    讓我們看看它內部是如何運作的:

    當渲染引擎解析 HTML 並遇到 <script> 時標籤,它會取得腳本並將其交給 JavaScript 引擎。 JavaScript 引擎透過將執行上下文推入呼叫堆疊來開始執行腳本。 <br><br></script>

    JavaScript 依賴瀏覽器提供的 Web API 來處理非同步任務,而不會阻塞主執行緒。其中包括計時器(setTimeout、setInterval)、HTTP 請求(fetch、XMLHttpRequest)、DOM 事件等 API。當呼叫非同步操作時,JavaScript 引擎會將其連同回呼函數交給 Web API,並繼續執行其餘程式碼。一旦非同步任務完成,瀏覽器就會將回調推送到對應的任務佇列(微任務佇列或巨集任務佇列)。

    以下是事件循環如何管理此佇列以及渲染

    1。微任務佇列: Promises、MutationObserver 回呼等都放在這裡。該隊列具有最高優先權。呼叫堆疊為空後,事件循環檢查微任務佇列。它透過將佇列中的所有個微任務推入呼叫堆疊來執行,依序處理它們。如果任何微任務將新的微任務加入到佇列中,這些微任務也會在繼續之前進行處理。

    2。渲染: 一旦微任務佇列為空,渲染引擎可能會接管主執行緒並在必要時執行渲染。這包括更新 UI 以反映腳本執行和微任務處理期間所做的任何 DOM 變更。這是根據設備幀速率完成的,每幀一次,以優化性能。

    3 . Macrotask Queue: setTimeout、setInterval、DOM 事件、I/O 事件等的回呼都放在這裡。此隊列優先權最低。事件循環從該佇列中提取一個任務並執行它。執行此任務後,它會在拉動下一個巨集任務之前處理所有微任務和渲染。

    [呼叫堆疊為空] → [處理所有微任務] → [根據需要渲染] → [執行一個巨集任務] → 重複

在伺服器端:隨著客戶端處理更多的使用者介面和使用者交互,伺服器開始轉移焦點。伺服器開始透過 API 提供資料和業務邏輯。它們從提供靜態 HTML 檔案發展成為處理請求、與資料庫互動以及執行複雜計算以提供資料的強大引擎。他們不再僅僅為瀏覽器提供服務,而是開始為廣泛的客戶端(行動或桌面應用程式、其他伺服器等)提供服務。

休息:休息的概念開始流行。 REST(表述性狀態傳輸)是一種架構風格,為設計 Web 服務提供了一組指引和約束。總而言之,每個資源都由 URL 唯一標識,並且使用 GET、POST、PUT 和 DELETE 等標準 HTTP 方法在無狀態用戶端伺服器互動中操作這些資源。這有助於伺服器變得簡單、可擴展且高效。

隨著應用程式變得越來越流行,伺服器必須處理更多的資料處理和業務邏輯。應用程式伺服器和資料庫伺服器需要非常有效地處理資料。伺服器必須實施一些新技術來應對這種繁重的負載,例如伺服器端快取、負載平衡和可擴展性、微服務架構等。

JavaScript EveryWhere:隨著NodeJS(JavaScript 運行環境)的引入,現在Javascript 可以在瀏覽器之外運行,帶來了「JavaScript EveryWhere」(客戶端和伺服器端)的概念) 。同時,npm(節點套件管理器)也被引入,它可以幫助開發人員輕鬆共享 JavaScript 程式碼。有了這些,JS 生態系統快速發展,提供了專案所需的所有必要工具(框架、捆綁器、編譯器、轉譯器等)。

單頁應用程式: 現在,JavaScript 在用戶端進行 DOM 建立和操作,因此需要框架來更有效地建立複雜的應用程式。輸入 Angular、React 等框架。這是客戶端腳本編寫的頂峰。基本上,在 SPA 中,僅從伺服器取得一個小的 HTML 文件,該文件由一個 <script> 中的整個應用程式的捆綁 Javascript 組成。標籤。該腳本自行負責所有使用者互動和 UI 更新,包括初始渲染。 </script>

仍面臨挑戰

儘管此階段解決了上一階段的挑戰,但它也帶來了新的挑戰,例如:

  • 較長的初始載入時間: SPA 通常意味著較大的初始JavaScript 捆綁包,這可能會減慢初始載入時間 — 尤其是在速度較慢的網路或設備上。即使用戶只想要其中的幾個部分,他們也必須獲得整個劇本——就像下載整部電影只是為了觀看預告片一樣。開發人員必須採用程式碼分割、延遲載入、樹搖、縮小等技術來優化它。

  • SEO 問題: 由於大多數內容是動態產生的,搜尋引擎很難對這些網站建立索引。當 Google 的抓取工具無法看到您的網站時,很難引起注意。伺服器端渲染 (SSR) 和預先渲染等技術可以解決這些問題。

  • JavaScript 疲勞: 隨著新的框架、工具和函式庫每天不斷湧現,開發人員厭倦了試圖趕上。跟上最新潮流就像在永不停歇的跑步機上跑步!而且選擇正確的堆疊也變得非常困難,有這麼多的選擇。

  • 更快,但更慢:伺服器端和客戶端效能都在提高,但沒有達到開發人員希望給用戶留下深刻印象的程度。此外,儘管瀏覽器速度快且功能強大,但它們的速度或功能不如本機應用程式。例如,您無法建立遊戲或影片編輯器等複雜應用程式。

第四階段:現代網路及其他

歡迎來到網頁開發的現代時代 -網路比以往任何時候都更加動態、強大且以使用者為中心的時代。讓我們討論一下目前正在發生的一些事情,這些事情可能會解決前一階段的挑戰。

沒有單一完美的渲染解決方案

經過上一階段,我們發現沒有一個適合所有人的完美渲染策略。我們必須根據我們的要求和約束選擇正確的、有時是混合的渲染策略。這裡有一些這樣的渲染策略

  1. 靜態網站產生(SSG): 與客戶端渲染(CSR) 不同,其中JavaScript 在使用者瀏覽器中建立HTML,SSG 在建置時產生整個HTML 文件,並為這些預先產生的靜態提供服務根據要求向使用者提供HTML、CSS、JS 檔案。我們甚至可以使用CDN來加快響應速度。

    它解決了初始載入時間較長和 SEO 問題等問題。它還具有非常快速的首次內容繪製。我們不必太擔心擴充問題,因為靜態檔案可以輕鬆地透過 CDN 提供服務。如果我們網站的大部分內容都是靜態的,我們可以選擇這種策略。但是,如果內容更加動態且特定於用戶,那麼這將無法正常運作。在這些情況下,我們可以選擇使用 SSG 和 CSR 與 Hydration 的混合方法,如下所述。您還可以查看 JAMStack,它解釋了有關使用 SSG 與無伺服器 API 和 Edge 函數的更多資訊。

  2. 伺服器端渲染(SSR):與第二階段有點類似,但這裡,業務邏輯與客戶端腳本分離。基本上,我們不是在瀏覽器上執行腳本並產生 HTML,而是在伺服器上執行腳本來產生 HTML,並根據每個使用者請求將其提供給瀏覽器。

    同樣,儘管它解決了較長的初始載入時間和 SEO 問題等問題,但它增加了伺服器負載。此外,我們大多數人都不希望每次使用者互動時都重新載入頁面,因此我們必須採用混合方法,包括 CSR 和 Hydration。

Hydration: 基本上,我們首先提供靜態 HTML 檔案來渲染,並透過在初始渲染後執行 JavaScript 來新增使用者互動性。這個將靜態網頁轉換為動態網頁的過程稱為水化。水合後,該應用程式的行為類似於 CSR 應用程式。

水合作用帶來了一些問題,使用者無法在看到內容後立即與其互動。他們必須等到該腳本下載並運行,這又增加了與 CSR 類似的相同開銷時間。為了緩解這種情況,出現了漸進式水合和部分水合等新的水合方法,但這些方法很難實施。

Next.js、Nuxt.js、Gatsby 和 React 等現代框架提供了多種渲染策略,以及增量靜態再生和串流 SSR 等新技術。


很累吧!是的,我知道,但是快完成了。還有許多已新增或提議的現有 Web API。雖然我們無法涵蓋所有這些,但請查看一些值得注意的 API,包括 Web Workers、IndexedDB 和共用儲存。

但是我們可以對以下兩種主要的網路技術感到興奮

WebAssembly(Wasm)

儘管現代 JavaScript 引擎正在努力讓 JS 更快,但主要瓶頸在於 JS 是一種動態類型和非編譯語言。這意味著我們不能依賴 JS 來進行真正需要大量效能的運算。這就是 WebAssembly 的用武之地。 WebAssembly 是一種由 C、C 和 Rust 等語言編寫的程式碼產生的二進位指令格式,無需外掛程式即可在所有現代瀏覽器上以接近原生的速度運行。

Wasm 與 JavaScript 一起工作,允許在它們之間呼叫函數。它尚不支援直接操作 DOM 或使用其他 Web API,但正在進行的開發旨在盡快添加此功能。 Wasm 可用於任何性能密集型 Web 應用程序,例如遊戲、圖像處理、影片編輯等。

漸進式網頁應用程式 (PWA)

有了這個廣泛的Web生態系統,為什麼我們不能建立一個類似原生的Web應用程式呢?漸進式 Web 應用程式是一種可以直接從瀏覽器安裝的 Web 應用程序,其工作方式類似於本機應用程序,提供離線支援、推播通知等。它們透過一個程式碼庫跨平台提供快速、引人入勝且可靠的體驗。

PWA 的一個關鍵元件是 Service Worker ,它獨立於主瀏覽器執行緒執行後台腳本。它可以充當 Web 應用程式、瀏覽器和伺服器之間的代理。 Service Worker 可以控制請求的處理方式並延遲某些操作,直到使用者擁有穩定的連線。這允許我們使用快取 API 快取資源,因此即使裝置離線或網路速度較慢時也可以提供內容,然後在重新上線後與伺服器同步。

但是,並非所有功能都得到跨瀏覽器的統一支援。建置 PWA 需要仔細規劃快取策略和離線行為。此外,與本機應用程式相比,PWA 可能還無法存取所有裝置功能,但這種情況正在擴大。


網路尚不完美,但當我們展望未來時,網路、本機和桌面應用程式之間的界線繼續模糊。新興技術如此之多,可能性是無限的。

部落格到此結束。如果我錯了或錯過了什麼,請告訴我。不斷探索,不斷學習。再見!

以上是網路技術和瀏覽器的演變的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn