第三單元 管道與中間件

来源:https://www.cnblogs.com/xuyubing/archive/2023/12/06/17878998.html
-Advertisement-
Play Games

1. 什麼是中間件 在ASP.NET Core中,中間件(Middleware)是一個可以處理HTTP請求或響應的軟體管道。 ASP.NET Core中給中間件組件的定位是具有非常特定的用途。例如,我們可能有需要一個中間件組件驗證用戶,另一個中間件來處理錯誤,另一個中間件來提供靜態文件,如JavaS ...


1. 什麼是中間件

在ASP.NET Core中,中間件(Middleware)是一個可以處理HTTP請求或響應的軟體管道。 ASP.NET Core中給中間件組件的定位是具有非常特定的用途。例如,我們可能有需要一個中間件組件驗證用戶,另一個中間件來處理錯誤,另一個中間件來提供靜態文件,如JavaScript文件,CSS文件,圖片等等。

中間件就是用於組成應用程式管道來處理請求和響應的組件 。

中間件可以認為有兩個基本的職責:

  1. 選擇是否將請求傳遞給管道中的下一個中間件。

  2. 可以在管道中的下一個中間件前後執行一些工作。

我們使用這些中間件組件在ASP.NET Core中設置請求處理管道,而正是這管道決定瞭如何處理請求。 而請求管道是由Startup.cs文件中的Configure()方法進行配置,它也是應用程式啟動的一個重要部分。

// 配置http 請求管道,由運行時調用
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage(); // 渲染錯誤頁中間件
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
    }
    app.UseStaticFiles(); // 使用靜態文件中間件
    
    app.UseRouting(); // 使用路由中間件
​
    app.UseAuthorization(); // 使用授權中間件
    // 終端節點中間件
    app.UseEndpoints(endpoints =>
                     {
                         endpoints.MapControllerRoute(
                             name: "default",
                             pattern: "{controller=Home}/{action=Index}/{id?}");
                     });
}
 

 

2. 中間件處理流程-請求管道

.Net Core管道(pipeline)是什麼?

簡單來說,就是從發起請求到返回結果的一個過程,在.Net Core中這裡面的處理是由中間件(middleware)來完成。 管道機制解釋 用戶在發起請求後,系統會自動生成一個請求管道(request pipeline),在這個請求管道中,可以通過run、map和use方法來配置請求委托(RequestDelegate),而在單獨的請求委托中定義的可重用的類和並行的匿名方法即為中間件,也叫做中間件組件。當發起請求後,系統會創建一個請求管道,在這個管道中,每一個中間件都會按順序處理(可能會執行,也可能不會被執行,取決於具體的業務邏輯),等最後一個中間件處理完後,又會按照相反的方向返回最終的處理結果。

例如,如果您有一個日誌記錄中間件,它可能只是記錄請求的時間,它處理完畢後將請求傳遞給下一個中間件以進行進一步處理。

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews(); // 添加控制器服務
}


public void Configure(IApplicationBuilder app, IWebHostEnvironment env,ILogger<Startup> logger)
{
    app.UseRouting();// 添加路由服務

    app.Use(next =>
            {
                logger.LogInformation("第1個中間件"); // 啟動時執行,只執行一次
                
                // 每次請求都會執行一次
                return async context =>
                {
                    logger.LogInformation("第1個中間件1-before");
                    await next(context);
                    logger.LogInformation("第1個中間件1-after");
                };
            });

    app.Use(next =>
            {
                logger.LogInformation("第2個中間件");// 啟動時執行,只執行一次

                 // 每次請求都會執行一次
                return async context =>
                {
                    logger.LogInformation("第2個中間件2-before");
                    await next(context);
                    logger.LogInformation("第2個中間件2-after");
                };
            });

    app.Use(next =>
            {
                logger.LogInformation("第3個中間件");// 啟動時執行,只執行一次

                 // 每次請求都會執行一次
                return async context =>
                {
                    logger.LogInformation("第3個中間件3-before");
                    await next(context);
                    logger.LogInformation("第3個中間件3-after");
                };
            });
    
    // 使用終端節點中間件會短路後面的中件間,所以,這個中間件最好放在最後
    app.UseEndpoints(endpoints =>
                     {
                         endpoints.MapControllerRoute(
                             name: "default",
                             pattern: "{controller=Home}/{action=Index}/{id?}");
                     });
}
info: Step3.Empty.Startup[0]
      第3個中間件
info: Step3.Empty.Startup[0]
      第2個中間件
info: Step3.Empty.Startup[0]
      第1個中間件

// 發起請求之後
info: Step3.Empty.Startup[0]
      第1個中間件1-before
info: Step3.Empty.Startup[0]
      第2個中間件2-before
info: Step3.Empty.Startup[0]
      第3個中間件3-before
info: Step3.Empty.Startup[0]
      第3個中間件3-after
info: Step3.Empty.Startup[0]
      第2個中間件2-after
info: Step3.Empty.Startup[0]
      第1個中間件1-after

 

中間件順序

下圖顯示了 ASP.NET Core MVC 和 Razor Pages 應用的完整請求處理管道。 你可以在典型應用中瞭解現有中間件的順序,以及在哪裡添加自定義中間件。 你可以完全控制如何重新排列現有中間件,或根據場景需要註入新的自定義中間件。

 

3. 什麼是短路

中間件組件可以處理請求, 並決定不調用管道中的下一個中間件,從而使管道短路,官方微軟給了一個英文的名字叫“terminal middleware ”,翻譯為“終端中間件”。短路通常是被允許的,因為它可以避免一些不必要的工作。 例如, 如果請求的是像圖像或 css 文件這樣的靜態文件, 則 StaticFiles 中間件可以處理和服務該請求並使管道中的其餘部分短路。這個意思就是說,在我們的示例中, 如果請求是針對靜態文件, 則 Staticile 中間件不會調用 MVC 中間件,避免一些無謂的操作。

public void Configure(IApplicationBuilder app, IWebHostEnvironment env,ILogger<Startup> logger)
{
    app.UseRouting();

    app.Use(next =>
            {
                logger.LogInformation("第1個中間件");

                return async context =>
                {
                    logger.LogInformation("第1個中間件1-before");
                    await next(context);
                    logger.LogInformation("第1個中間件1-after");
                };
            });

    // 後面的中件間將不會再執行了
    app.Use(next =>
            {
                logger.LogInformation("第2個中間件");

                return async context =>
                {
                    logger.LogInformation("短路了");
                    // await next(context); // 沒有調用即表示短路了
                };
            });
    
    app.Use(next =>
            {
                logger.LogInformation("第3個中間件");

                return async context =>
                {
                    logger.LogInformation("第3個中間件3-before");
                    await next(context);
                    logger.LogInformation("第3個中間件3-after");
                };
            });

    app.UseEndpoints(endpoints =>
                     {
                         endpoints.MapControllerRoute(
                             name: "default",
                             pattern: "{controller=Home}/{action=Index}/{id?}");
                     });
}
輸出結果:

info: Step3.Empty.Startup[0]
      第3個中間件
info: Step3.Empty.Startup[0]
      第2個中間件
info: Step3.Empty.Startup[0]
      第1個中間件

// 發起請求之後
info: Step3.Empty.Startup[0]
      第1個中間件1-before
info: Step3.Empty.Startup[0]
      短路了
info: Step3.Empty.Startup[0]
      第1個中間件1-after

 

app.Use 與 app.Run 的區別

它倆都可以添加一個中間件至請求管道中。

  1. Use 有權決定是否執行下一個中間件,如果不執行,則出現短路情況

  2. Run 是直接短路,不會執行後面的中間件。

 

4. 常用的系統中間件

1. 路由中間件

ASP.NET Core 控制器使用路由中間件來匹配傳入請求的 URL 並將它們映射到操作。 若要設置路由模板,則必須執行添加如下中間件至執行管道.

// 添加控制器與視圖服務
builder.Services.AddControllersWithViews();


// ....上面省略一些代碼
app.UseRouting();

 

路由模板:

  • 在啟動時 Program.cs 或在屬性中定義。

  • 描述 URL 路徑如何與操作相匹配。

  • 用於生成鏈接的 URL。 生成的鏈接通常在響應中返回。

操作既支持傳統路由,也支持屬性路由。 通過在控制器或操作上放置路由可實現屬性路由。 有關詳細信息,請參閱混合路由

路由模板示例匹配 URI請求 URI…
hello /hello 僅匹配單個路徑 /hello
{Page=Home} / 匹配並將 Page 設置為 Home
{Page=Home} /Contact 匹配並將 Page 設置為 Contact
{controller}/{action}/{id?} /Products/List 映射到 Products 控制器和 List 操作。
{controller}/{action}/{id?} /Products/Details/123 映射到 Products 控制器和 Details 操作,並將 id 設置為 123。
{controller=Home}/{action=Index}/{id?} / 映射到 Home 控制器和 Index 方法。 id 將被忽略。
{controller=Home}/{action=Index}/{id?} /Products 映射到 Products 控制器和 Index 方法。 id 將被忽略。

設置傳統路由

app.UseRouting();
app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run(); // 必須添加一個終節點
路由模板 "{controller=Home}/{action=Index}/{id?}":

匹配 URL 路徑,例如 /Products/Details/5

通過標記路徑來提取路由值 { controller = Products, action = Details, id = 5 }。 如果應用有一個名為 ProductsController 的控制器和一個 Details 操作,則提取路由值會導致匹配:

public class ProductsController : Controller
{
    public IActionResult Details(int id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
}
MyDisplayRouteInfo 由 Rick.Docs.Samples.RouteInfo NuGet 包提供,會顯示路由信息。

/Products/Details/5 模型綁定 id = 5 的值,以將 id 參數設置為 5。 有關更多詳細信息,請參閱模型綁定。

{controller=Home} 將 Home 定義為預設 controller。

{action=Index} 將 Index 定義為預設 action。

{id?} 中的 ? 字元將 id 定義為可選。

預設路由參數和可選路由參數不必包含在 URL 路徑中進行匹配。 有關路由模板語法的詳細說明,請參閱路由模板參考。

匹配 URL 路徑 /。

生成路由值 { controller = Home, action = Index }。

controller 和 action 的值使用預設值。 id 不會生成值,因為 URL 路徑中沒有相應的段。 / 僅在存在 HomeController 和 Index 操作時匹配:

public class HomeController : Controller
{
    public IActionResult Index() { ... }
}
使用前面的控制器定義和路由模板,為以下 URL 路徑運行 HomeController.Index 操作:

/Home/Index/17

/Home/Index

/Home

/

URL 路徑 / 使用路由模板預設 Home 控制器和 Index 操作。 URL 路徑 /Home 使用路由模板預設 Index 操作。

簡便方法 MapDefaultControllerRoute:

app.MapDefaultControllerRoute();
替代:

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");
 

屬性路由
// 添加控制器與視圖服務
builder.Services.AddControllersWithViews();


// ....上面省略一些代碼 
// app.UseRouting(); // 此行代碼已經不需要了
app.MapControllers(); // 映射控制器
MapControllers 調用它來映射屬性路由控制器。

在以下示例中:

HomeController 匹配一組類似於預設傳統路由 {controller=Home}/{action=Index}/{id?} 匹配的 URL。

public class HomeController : Controller
{
    [Route("")]
    [Route("Home")]
    [Route("Home/Index")]
    [Route("Home/Index/{id?}")]
    public IActionResult Index(int? id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }

    [Route("Home/About")]
    [Route("Home/About/{id?}")]
    public IActionResult About(int? id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
}
將針對任意 URL 路徑 /、/Home、/Home/Index 或 /Home/Index/3 執行 HomeController.Index 操作。

此示例重點介紹屬性路由與傳統路由之間的主要編程差異。 屬性路由需要更多輸入才能指定路由。 傳統預設路由會更簡潔地處理路由。 但是,屬性路由允許並需要精確控制應用於每項操作的路由模板。

對於屬性路由,控制器和操作名稱在操作匹配中不起作用,除非使用標記替換。 以下示例匹配與上一個示例相同的 URL:

public class MyDemoController : Controller
{
    [Route("")]
    [Route("Home")]
    [Route("Home/Index")]
    [Route("Home/Index/{id?}")]
    public IActionResult MyIndex(int? id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }

    [Route("Home/About")]
    [Route("Home/About/{id?}")]
    public IActionResult MyAbout(int? id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
}
以下代碼對 action 和 controller 使用標記替換:

public class HomeController : Controller
{
    [Route("")]
    [Route("Home")]
    [Route("[controller]/[action]")]
    public IActionResult Index()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }

    [Route("[controller]/[action]")]
    public IActionResult About()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }
}
以下代碼將 [Route("[controller]/[action]")] 應用於控制器:

[Route("[controller]/[action]")]
public class HomeController : Controller
{
    [Route("~/")]
    [Route("/Home")]
    [Route("~/Home/Index")]
    public IActionResult Index()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }

    public IActionResult About()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }
}

 

在前面的代碼中,Index 方法模板必須將 /~/ 預置到路由模板。 應用於操作的以 /~/ 開頭的路由模板不與應用於控制器的路由模板合併。

有關路由模板選擇的信息,請參閱路由模板優先順序

 

路由約束(可選)

路由約束在傳入 URL 發生匹配時執行,URL 路徑標記為路由值。 路徑約束通常檢查通過路徑模板關聯的路徑值,並對該值是否為可接受做出對/錯決定。 某些路由約束使用路由值以外的數據來考慮是否可以路由請求。 例如,HttpMethodRouteConstraint 可以根據其 HTTP 謂詞接受或拒絕請求。 約束用於路由請求和鏈接生成。

警告

請勿將約束用於輸入驗證。 如果約束用於輸入驗證,則無效的輸入將導致 404(找不到頁面)響應。 無效輸入可能生成包含相應錯誤消息的 400 錯誤請求。 路由約束用於消除類似路由的歧義,而不是驗證特定路由的輸入。

下表演示示例路由約束及其預期行為:

約束示例匹配項示例說明
int {id:int} 123456789, -123456789 匹配任何整數
bool {active:bool} true, FALSE 匹配 truefalse。 不區分大小寫
datetime {dob:datetime} 2016-12-31, 2016-12-31 7:32pm 在固定區域性中匹配有效的 DateTime 值。 請參閱前面的警告。
decimal {price:decimal} 49.99, -1,000.01 在固定區域性中匹配有效的 decimal 值。 請參閱前面的警告。
double {weight:double} 1.234, -1,001.01e8 在固定區域性中匹配有效的 double 值。 請參閱前面的警告。
float {weight:float} 1.234, -1,001.01e8 在固定區域性中匹配有效的 float 值。 請參閱前面的警告。
guid {id:guid} CD2C1638-1638-72D5-1638-DEADBEEF1638 匹配有效的 Guid
long {ticks:long} 123456789, -123456789 匹配有效的 long
minlength(value) {username:minlength(4)} Rick 字元串必須至少為 4 個字元
maxlength(value) {filename:maxlength(8)} MyFile 字元串不得超過 8 個字元
length(length) {filename:length(12)} somefile.txt 字元串必須正好為 12 個字元
length(min,max) {filename:length(8,16)} somefile.txt 字元串必須至少為 8 個字元,且不得超過 16 個字元
min(value) {age:min(18)} 19 整數值必須至少為 18
max(value) {age:max(120)} 91 整數值不得超過 120
range(min,max) {age:range(18,120)} 91 整數值必須至少為 18,且不得超過 120
alpha {name:alpha} Rick 字元串必須由一個或多個字母字元組成,a-z,並區分大小寫。
regex(expression) {ssn:regex(^\\d{{3}}-\\d{{2}}-\\d{{4}}$)} 123-45-6789 字元串必須與正則表達式匹配。 請參閱有關定義正則表達式的提示。
required {name:required} Rick 用於強制在 URL 生成過程中存在非參數值

警告

如果使用 System.Text.RegularExpressions 處理不受信任的輸入,則傳遞一個超時。 惡意用戶可能會向 RegularExpressions 提供輸入,從而導致拒絕服務攻擊。 使用 RegularExpressions 的 ASP.NET Core 框架 API 會傳遞一個超時。

 

可向單個參數應用多個用冒號分隔的約束。 例如,以下約束將參數限製為大於或等於 1 的整數值:

[Route("users/{id:int:min(1)}")]
public User GetUserById(int id) { }

 

警告

驗證 URL 的路由約束並將轉換為始終使用固定區域性的 CLR 類型。 例如,轉換為 CLR 類型 intDateTime。 這些約束假定 URL 不可本地化。 框架提供的路由約束不會修改存儲於路由值中的值。 從 URL 中分析的所有路由值都將存儲為字元串。 例如,float 約束會嘗試將路由值轉換為浮點數,但轉換後的值僅用來驗證其是否可轉換為浮點數。

 

疑惑解答:

1. 當訪問一個Web 應用地址時,Asp.Net Core 是怎麼執行到ControllerAction的呢?

答:程式啟動的時候會把所有的Controller 中的Action 映射存儲到routeOptions 的集合中,Action 映射成Endpoint終結者 的RequestDelegate 委托屬性,最後通過UseEndPoints 添加EndpointMiddleware 中間件進行執行,同時這個中間件中的Endpoint 終結者路由已經是通過Rouing匹配後的路由。

2. EndPoint 跟普通路由又存在著什麼樣的關係?

答:Ednpoint 終結者路由是普通路由map 轉換後的委托路由,裡面包含了路由方法的所有元素信息EndpointMetadataCollectionRequestDelegate 委托。

3. UseRouing()UseAuthorization()UseEndpoints() 這三個中間件的關係是什麼呢?

答:UseRouing 中間件主要是路由匹配,找到匹配的終結者路由EndpointUseEndpoints 中間件主要針對UseRouing 中間件匹配到的路由進行 委托方法的執行等操作。 UseAuthorization 中間件主要針對 UseRouing 中間件中匹配到的路由進行攔截 做授權驗證操作等,通過則執行下一個中間件UseEndpoints(),具體的關係可以看下麵的流程圖:

 

上面流程圖中省略了一些部分,主要是把UseRouing 、UseAuthorization 、UseEndpoint 這三個中間件的關係突顯出來。

 

 

2. 異常中間件

UseExceptionHandler : 將中間件添加到管道,該中間件將捕獲異常,記錄異常,併在備用管道中重新執行請求。如果響應已啟動,則不會重新執行請求。

UseDeveloperExceptionPage: 從管道捕獲同步和非同步異常實例,並生成 HTML 錯誤響應。

if (!app.Environment.IsDevelopment()) // 非開發環境下,可以顯示自定義錯誤頁
{
    app.UseExceptionHandler("/Home/Error");
}
else
{
    app.UseDeveloperExceptionPage(); // 開發人員錯誤頁
}

 

 

3. 靜態資源中間件

預設情況下,靜態文件(如 HTML、CSS、圖像和 JavaScript)是 ASP.NET Core 應用直接提供給客戶端的資產。

靜態文件存儲在項目的 Web 根目錄中。 預設目錄為 {content root}/wwwroot,但可通過 UseWebRoot 方法更改目錄。 有關詳細信息,請參閱內容根目錄Web 根目錄

Web 應用程式項目模板包含 wwwroot 文件夾中的多個文件夾:

  • wwwroot

    • css 樣式文件

    • js 腳本文件

    • lib 第三方前端庫

    • images 圖片文件

 

預設 Web 應用模板在 Program.cs 中調用

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 作者:Lxlxxx 鏈接:https://juejin.cn/post/7221461552343072828 前言 繼上次線上CPU出現了報警,這次服務又開始整活了,風平浪靜了沒幾天,看生產日誌服務的運行的時候,頻繁的出現OutOfMemoryError,就是我們俗稱的OOM,這可還行! 頻繁的O ...
  • 上一篇介紹了scikit-learn中的幾個玩具數據集,本篇介紹scikit-learn提供的一些真實的數據集。玩具數據集:scikit-learn 基礎(01)--『數據載入』之玩具數據集 1. 獲取數據集 與玩具數據集不同,真實的數據集的數據不僅數據特征多,而且數據量也比較大,所以沒有直接包含在 ...
  • 在今天的課上,我們深入討論了封裝、反射和單例模式這幾個重要的概念。我不想過多地贅述它們的細節,但是請大家務必記住它們的基本語法規則,因為這也是面向對象章節的結束。我希望大家能夠牢牢掌握這些知識點,為未來的學習打下堅實的基礎。 ...
  • 外接矩形、外接圓: 1 import cv2 2 import numpy 3 4 img = cv2.imread('../img/img.png', -1) 5 ret, thresh = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY) 6 con ...
  • 1. _Layout.cshtml 佈局頁 佈局視圖和我們在Asp.Net MVC一樣,佈局視圖_Layout.cshtml使得所有視圖保持一致的外觀變得更加容易,因為我們只有一個要修改的佈局視圖文件,更改後將立即反映在整個應用程式的所有視圖中。 在 ASP.NET Core MVC 中,有一些視圖 ...
  • 如果是首次安裝Dev只需要下麵兩步流程就可以 第一步安裝試用的最新版 Devexpress 22.2.4這步看直接去官網,安裝官方試用的就可以 第二步安裝破解補丁關閉防火牆或360 然後打開 DevExpress.Universal.Patch 選擇22.2 版本 和對應的visual studio ...
  • create database MvcUnit4; go use MvcUnit4; go create table Product ( Id bigint primary key, ProductName varchar(30), CategoryName varchar(30), Price d ...
  • 前言 上一篇,我們實現了基於 DotNetty 的通信基礎模塊的搭建,本篇,主要實現待發佈 Web 項目的集成。 創建待發佈項目 為了測試, 我創建了一個基於 .NET 4.8 的 Web 項目 OpenDeploy.TestWebProject 我本機的代碼倉儲路徑是: D:\Projects\B ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...