ASP.NET Core Web API 最佳實踐指南

来源:https://www.cnblogs.com/hippieZhou/archive/2019/12/19/11966373.html
-Advertisement-
Play Games

原文地址: "ASP.NET Core Web API Best Practices Guide" 介紹 當我們編寫一個項目的時候,我們的主要目標是使它能如期運行,並儘可能地滿足所有用戶需求。 但是,你難道不認為創建一個能正常工作的項目還不夠嗎?同時這個項目不應該也是可維護和可讀的嗎? 事實證明,我 ...


原文地址: ASP.NET-Core-Web-API-Best-Practices-Guide

介紹

當我們編寫一個項目的時候,我們的主要目標是使它能如期運行,並儘可能地滿足所有用戶需求。

但是,你難道不認為創建一個能正常工作的項目還不夠嗎?同時這個項目不應該也是可維護和可讀的嗎?

事實證明,我們需要把更多的關註點放到我們項目的可讀性和可維護性上。這背後的主要原因是我們或許不是這個項目的唯一編寫者。一旦我們完成後,其他人也極有可能會加入到這裡面來。

因此,我們應該把關註點放到哪裡呢?

在這一份指南中,關於開發 .NET Core Web API 項目,我們將敘述一些我們認為會是最佳實踐的方式。進而讓我們的項目變得更好和更加具有可維護性。

現在,讓我們開始想一些可以應用到 ASP.NET Web API 項目中的一些最佳實踐。

Startup 類 和 服務配置

STARTUP CLASS AND THE SERVICE CONFIGURATION

Startup 類中,有兩個方法:ConfigureServices 是用於服務註冊,Configure 方法是嚮應用程式的請求管道中添加中間件。

因此,最好的方式是保持 ConfigureServices 方法簡潔,並且儘可能地具有可讀性。當然,我們需要在該方法內部編寫代碼來註冊服務,但是我們可以通過使用 擴展方法 來讓我們的代碼更加地可讀和可維護。

例如,讓我們看一個註冊 CORS 服務的不好方式:

public void ConfigureServices(IServiceCollection services)
{
    services.AddCors(options => 
    {
        options.AddPolicy("CorsPolicy", builder => builder.AllowAnyOrigin()
            .AllowAnyMethod()
            .AllowAnyHeader()
            .AllowCredentials());
    });
}

儘管這種方式看起來挺好,也能正常地將 CORS 服務註冊成功。但是想象一下,在註冊了十幾個服務之後這個方法體的長度。

這樣一點也不具有可讀性。

一種好的方式是通過在擴展類中創建靜態方法:

public static class ServiceExtensions
{
    public static void ConfigureCors(this IServiceCollection services)
    {
        services.AddCors(options =>
        {
            options.AddPolicy("CorsPolicy", builder => builder.AllowAnyOrigin()
                .AllowAnyMethod()
                .AllowAnyHeader()
                .AllowCredentials());
        });
    }
}

然後,只需要調用這個擴展方法即可:

public void ConfigureServices(IServiceCollection services)
{
    services.ConfigureCors();
}

瞭解更多關於 .NET Core 的項目配置,請查看:.NET Core Project Configuration

項目組織

PROJECT ORGANIZATION

我們應該嘗試將我們的應用程式拆分為多個小項目。通過這種方式,我們可以獲得最佳的項目組織方式,並能將關註點分離(SoC)。我們的實體、契約、訪問資料庫操作、記錄信息或者發送郵件的業務邏輯應該始終放在單獨的 .NET Core 類庫項目中。

應用程式中的每個小項目都應該包含多個文件夾用來組織業務邏輯。

這裡有個簡單的示例用來展示一個複雜的項目應該如何組織:

基於環境的設置

ENVIRONMENT BASED SETTINGS

當我們開發應用程式時,它處於開發環境。但是一旦我們發佈之後,它將處於生產環境。因此,將每個環境進行隔離配置往往是一種好的實踐方式。

在 .NET Core 中,這一點很容易實現。

一旦我們創建好了項目,就已經有一個 appsettings.json 文件,當我們展開它時會看到 appsettings.Development.json 文件:

此文件中的所有設置將用於開發環境。

我們應該添加另一個文件 appsettings.Production.json,將其用於生產環境:

生產文件將位於開發文件下麵。

設置修改後,我們就可以通過不同的 appsettings 文件來載入不同的配置,取決於我們應用程式當前所處環境,.NET Core 將會給我們提供正確的設置。更多關於這一主題,請查閱:Multiple Environments in ASP.NET Core.

數據訪問層

DATA ACCESS LAYER

在一些不同的示例教程中,我們可能看到 DAL 的實現在主項目中,並且每個控制器中都有實例。我們不建議這麼做。

當我們編寫 DAL 時,我們應該將其作為一個獨立的服務來創建。在 .NET Core 項目中,這一點很重要,因為當我們將 DAL 作為一個獨立的服務時,我們就可以將其直接註入到 IOC(控制反轉)容器中。IOC 是 .NET Core 內置功能。通過這種方式,我們可以在任何控制器中通過構造函數註入的方式來使用。

public class OwnerController: Controller
{
    private readonly IRepository _repository;
    public OwnerController(IRepository repository)
    {
        _repository = repository;
    }
}

控制器

CONTROLLERS

控制器應該始終儘量保持整潔。我們不應該將任何業務邏輯放置於內。

因此,我們的控制器應該通過構造函數註入的方式接收服務實例,並組織 HTTP 的操作方法(GET,POST,PUT,DELETE,PATCH...):

public class OwnerController : Controller
{
    private readonly ILoggerManager _logger;
    private readonly IRepository _repository;
    public OwnerController(ILoggerManager logger, IRepository repository)
    {
        _logger = logger;
        _repository = repository;
    }

    [HttpGet]
    public IActionResult GetAllOwners()
    {
    }
    [HttpGet("{id}", Name = "OwnerById")]
    public IActionResult GetOwnerById(Guid id)
    {
    }
    [HttpGet("{id}/account")]
    public IActionResult GetOwnerWithDetails(Guid id)
    {
    }
    [HttpPost]
    public IActionResult CreateOwner([FromBody]Owner owner)
    {
    }
    [HttpPut("{id}")]
    public IActionResult UpdateOwner(Guid id, [FromBody]Owner owner)
    {
    }
    [HttpDelete("{id}")]
    public IActionResult DeleteOwner(Guid id)
    {
    }
}

我們的 Action 應該儘量保持簡潔,它們的職責應該包括處理 HTTP 請求,驗證模型,捕捉異常和返迴響應。

[HttpPost]
public IActionResult CreateOwner([FromBody]Owner owner)
{
    try
    {
        if (owner.IsObjectNull())
        {
            return BadRequest("Owner object is null");
        }
        if (!ModelState.IsValid)
        {
            return BadRequest("Invalid model object");
        }
        _repository.Owner.CreateOwner(owner);
        return CreatedAtRoute("OwnerById", new { id = owner.Id }, owner);
    }
    catch (Exception ex)
    {
        _logger.LogError($"Something went wrong inside the CreateOwner action: { ex} ");
        return StatusCode(500, "Internal server error");
    }
}

在大多數情況下,我們的 action 應該將 IActonResult 作為返回類型(有時我們希望返回一個特定類型或者是 JsonResult ...)。通過使用這種方式,我們可以很好地使用 .NET Core 中內置方法的返回值和狀態碼。

使用最多的方法是:

  • OK => returns the 200 status code
  • NotFound => returns the 404 status code
  • BadRequest => returns the 400 status code
  • NoContent => returns the 204 status code
  • Created, CreatedAtRoute, CreatedAtAction => returns the 201 status code
  • Unauthorized => returns the 401 status code
  • Forbid => returns the 403 status code
  • StatusCode => returns the status code we provide as input

處理全局異常

HANDLING ERRORS GLOBALLY

在上面的示例中,我們的 action 內部有一個 try-catch 代碼塊。這一點很重要,我們需要在我們的 action 方法體中處理所有的異常(包括未處理的)。一些開發者在 action 中使用 try-catch 代碼塊,這種方式明顯沒有任何問題。但我們希望 action 儘量保持簡潔。因此,從我們的 action 中刪除 try-catch ,並將其放在一個集中的地方會是一種更好的方式。.NET Core 給我們提供了一種處理全局異常的方式,只需要稍加修改,就可以使用內置且完善的的中間件。我們需要做的修改就是在 Startup 類中修改 Configure 方法:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseExceptionHandler(config => 
    {
        config.Run(async context => 
        {
            context.Response.StatusCode = 500;
            context.Response.ContentType = "application/json";

            var error = context.Features.Get<IExceptionHandlerFeature>();
            if (error != null)
            {
                var ex = error.Error;
                await context.Response.WriteAsync(new ErrorModel
                {
                    StatusCode = 500,
                    ErrorMessage = ex.Message
                }.ToString());
            }
        });
    });

    app.UseRouting();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
}

我們也可以通過創建自定義的中間件來實現我們的自定義異常處理:

// You may need to install the Microsoft.AspNetCore.Http.Abstractions package into your project
public class CustomExceptionMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger<CustomExceptionMiddleware> _logger;
    public CustomExceptionMiddleware(RequestDelegate next, ILogger<CustomExceptionMiddleware> logger)
    {
        _next = next;
        _logger = logger;
    }

    public async Task Invoke(HttpContext httpContext)
    {
        try
        {
            await _next(httpContext);
        }
        catch (Exception ex)
        {
            _logger.LogError("Unhandled exception....", ex);
            await HandleExceptionAsync(httpContext, ex);
        }
    }

    private Task HandleExceptionAsync(HttpContext httpContext, Exception ex)
    {
        //todo
        return Task.CompletedTask;
    }
}

// Extension method used to add the middleware to the HTTP request pipeline.
public static class CustomExceptionMiddlewareExtensions
{
    public static IApplicationBuilder UseCustomExceptionMiddleware(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<CustomExceptionMiddleware>();
    }
}

之後,我們只需要將其註入到應用程式的請求管道中即可:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseCustomExceptionMiddleware();
}

使用過濾器移除重覆代碼

USING ACTIONFILTERS TO REMOVE DUPLICATED CODE

ASP.NET Core 的過濾器可以讓我們在請求管道的特定狀態之前或之後運行一些代碼。因此如果我們的 action 中有重覆驗證的話,可以使用它來簡化驗證操作。

當我們在 action 方法中處理 PUT 或者 POST 請求時,我們需要驗證我們的模型對象是否符合我們的預期。作為結果,這將導致我們的驗證代碼重覆,我們希望避免出現這種情況,(基本上,我們應該盡我們所能避免出現任何代碼重覆。)我們可以在代碼中通過使用 ActionFilter 來代替我們的驗證代碼:

if (!ModelState.IsValid)
{
    //bad request and logging logic
}

我們可以創建一個過濾器:

public class ModelValidationAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext context)
    {
        if (!context.ModelState.IsValid)
        {
            context.Result = new BadRequestObjectResult(context.ModelState);
        }
    }
}

然後在 Startup 類的 ConfigureServices 函數中將其註入:

services.AddScoped<ModelValidationAttribute>();

現在,我們可以將上述註入的過濾器應用到我們的 action 中。

Microsoft.AspNetCore.All 元包

MICROSOFT.ASPNETCORE.ALL META-PACKAGE

註:如果你使用的是 2.1 和更高版本的 ASP.NET Core。建議使用 Microsoft.AspNetCore.App 包,而不是 Microsoft.AspNetCore.All。這一切都是出於安全原因。此外,如果使用 2.1 版本創建新的 WebAPI 項目,我們將自動獲取 AspNetCore.App 包,而不是 AspNetCore.All。

這個元包包含了所有 AspNetCore 的相關包,EntityFrameworkCore 包,SignalR 包(version 2.1) 和依賴框架運行的支持包。採用這種方式創建一個新項目很方便,因為我們不需要手動安裝一些我們可能使用到的包。

當然,為了能使用 Microsoft.AspNetCore.all 元包,需要確保你的機器安裝了 .NET Core Runtime。

路由

ROUTING

在 .NET Core Web API 項目中,我們應該使用屬性路由代替傳統路由,這是因為屬性路由可以幫助我們匹配路由參數名稱與 Action 內的實際參數方法。另一個原因是路由參數的描述,對我們而言,一個名為 "ownerId" 的參數要比 "id" 更加具有可讀性。

我們可以使用 [Route] 屬性來在控制器的頂部進行標註:

[Route("api/[controller]")]
public class OwnerController : Controller
{
    [Route("{id}")]
    [HttpGet]
    public IActionResult GetOwnerById(Guid id)
    {
    }
}

還有另一種方式為控制器和操作創建路由規則:

[Route("api/owner")]
public class OwnerController : Controller
{
    [Route("{id}")]
    [HttpGet]
    public IActionResult GetOwnerById(Guid id)
    {
    }
}

對於這兩種方式哪種會好一些存在分歧,但是我們經常建議採用第二種方式。這是我們一直在項目中採用的方式。

當我們談論路由時,我們需要提到路由的命名規則。我們可以為我們的操作使用描述性名稱,但對於 路由/節點,我們應該使用 NOUNS 而不是 VERBS。

一個較差的示例:

[Route("api/owner")]
public class OwnerController : Controller
{
    [HttpGet("getAllOwners")]
    public IActionResult GetAllOwners()
    {
    }
    [HttpGet("getOwnerById/{id}"]
    public IActionResult GetOwnerById(Guid id)
    {
    }
}

一個較好的示例:

[Route("api/owner")]
public class OwnerController : Controller
{
    [HttpGet]
    public IActionResult GetAllOwners()
    {
    }
    [HttpGet("{id}"]
    public IActionResult GetOwnerById(Guid id)
    {
    }
}

更多關於 Restful 實踐的細節解釋,請查閱:Top REST API Best Practices

日誌

LOGGING

如果我們打算將我們的應用程式發佈到生產環境,我們應該在合適的位置添加一個日誌記錄機制。在生產環境中記錄日誌對於我們梳理應用程式的運行很有幫助。

.NET Core 通過繼承 ILogger 介面實現了它自己的日誌記錄。通過藉助依賴註入機制,它可以很容易地使用。

public class TestController: Controller
{
    private readonly ILogger _logger;
    public TestController(ILogger<TestController> logger)
    {
        _logger = logger;
    }
}

然後,在我們的 action 中,我們可以通過使用 _logger 對象藉助不同的日誌級別來記錄日誌。

.NET Core 支持使用於各種日誌記錄的 Provider。因此,我們可能會在項目中使用不同的 Provider 來實現我們的日誌邏輯。

NLog 是一個很不錯的可以用於我們自定義的日誌邏輯類庫,它極具擴展性。支持結構化日誌,且易於配置。我們可以將信息記錄到控制台,文件甚至是資料庫中。

想瞭解更多關於該類庫在 .NET Core 中的應用,請查閱:.NET Core series – Logging With NLog.

Serilog 也是一個很不錯的類庫,它適用於 .NET Core 內置的日誌系統。

加密

CRYPTOHELPER

我們不會建議將密碼以明文形式存儲到資料庫中。處於安全原因,我們需要對其進行哈希處理。這超出了本指南的內容範圍。互聯網上有大量哈希演算法,其中不乏一些不錯的方法來將密碼進行哈希處理。

但是如果需要為 .NET Core 的應用程式提供易於使用的加密類庫,CryptoHelper 是一個不錯的選擇。

CryptoHelper 是適用於 .NET Core 的獨立密碼哈希庫,它是基於 PBKDF2 來實現的。通過創建 Data Protection 棧來將密碼進行哈希化。這個類庫在 NuGet 上是可用的,並且使用也很簡單:

using CryptoHelper;

// Hash a password
public string HashPassword(string password)
{
    return Crypto.HashPassword(password);
}

// Verify the password hash against the given password
public bool VerifyPassword(string hash, string password)
{
    return Crypto.VerifyHashedPassword(hash, password);
}

內容協商

CONTENT NEGOTIATION

預設情況下,.NET Core Web API 會返回 JSON 格式的結果。大多數情況下,這是我們所希望的。

但是如果客戶希望我們的 Web API 返回其它的響應格式,例如 XML 格式呢?

為瞭解決這個問題,我們需要進行服務端配置,用於按需格式化我們的響應結果:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers().AddXmlSerializerFormatters();
}

但有時客戶端會請求一個我們 Web API 不支持的格式,因此最好的實踐方式是對於未經處理的請求格式統一返回 406 狀態碼。這種方式也同樣能在 ConfigureServices 方法中進行簡單配置:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers(options => options.ReturnHttpNotAcceptable = true).AddXmlSerializerFormatters();
}

我們也可以創建我們自己的格式化規則。

這一部分內容是一個很大的主題,如果你希望瞭解更多,請查閱:Content Negotiation in .NET Core

使用 JWT

USING JWT

現如今的 Web 開發中,JSON Web Tokens (JWT) 變得越來越流行。得益於 .NET Core 內置了對 JWT 的支持,因此實現起來非常容易。JWT 是一個開發標準,它允許我們以 JSON 格式在服務端和客戶端進行安全的數據傳輸。

我們可以在 ConfigureServices 中配置 JWT 認證:

public void ConfigureServices(IServiceCollection services)
{
    services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearer(options => 
        {
            options.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuer = true,
                ValidIssuer = _authToken.Issuer,

                ValidateAudience = true,
                ValidAudience = _authToken.Audience,

                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_authToken.Key)),

                RequireExpirationTime = true,
                ValidateLifetime = true,

                //others
            };
        });
}

為了能在應用程式中使用它,我們還需要在 Configure 中調用下麵一段代碼:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseAuthentication();
}

此外,創建 Token 可以使用如下方式:

var securityToken = new JwtSecurityToken(
                claims: new Claim[]
                {
                    new Claim(ClaimTypes.NameIdentifier,user.Id),
                    new Claim(ClaimTypes.Email,user.Email)
                },
                issuer: _authToken.Issuer,
                audience: _authToken.Audience,
                notBefore: DateTime.Now,
                expires: DateTime.Now.AddDays(_authToken.Expires),
                signingCredentials: new SigningCredentials(
                    new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_authToken.Key)),
                    SecurityAlgorithms.HmacSha256Signature));

Token = new JwtSecurityTokenHandler().WriteToken(securityToken)

基於 Token 的用戶驗證可以在控制器中使用如下方式:

var auth = await HttpContext.AuthenticateAsync();
var id = auth.Principal.Claims.FirstOrDefault(x => x.Type.Equals(ClaimTypes.NameIdentifier))?.Value;

我們也可以將 JWT 用於授權部分,只需添加角色聲明到 JWT 配置中即可。

更多關於 .NET Core 中 JWT 認證和授權部分,請查閱:authentication-aspnetcore-jwt-1authentication-aspnetcore-jwt-2

總結

讀到這裡,可能會有朋友對上述一些最佳實踐不是很認同,因為全篇都沒有談及更切合項目的實踐指南,比如 TDDDDD 等。但我個人認為上述所有的最佳實踐是基礎,只有把這些基礎掌握了,才能更好地理解一些更高層次的實踐指南。萬丈高樓平地起,所以你可以把這看作是一篇面向新手的最佳實踐指南。

在這份指南中,我們的主要目的是讓你熟悉關於使用 .NET Core 開發 web API 項目時的一些最佳實踐。這裡面的部分內容在其它框架中也同樣適用。因此,熟練掌握它們很有用。

非常感謝你能閱讀這份指南,希望它能對你有所幫助。


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

-Advertisement-
Play Games
更多相關文章
  • 我們搜索一下yum庫關於nginx的rpm包:yum list | grep nginx 找到rpm安裝包,我們就可以使用yum直接安裝了:yum install nginx 修改nginx配置文件:vi /etc/nginx/nginx.conf 註釋掉下麵的配置: 創建一個netcore.con ...
  • WPF中一些圖片處理方案整理,可以大致實現類似PS的一些基本功能:移動,裁剪,摳圖,背景橡皮擦等等 ...
  • Protected 在基類中定義後,能被派生類調用,但是不能被其他類調用。 virtual 在基類中定義後,在派生類中能被重寫。 using System; using System.Collections.Generic; using System.Text; namespace 繼承 { cla ...
  • 一丶簡單介紹下目錄結構和項目依賴,如圖 二丶主要核心自定義代碼 1. 添加自定義實現類 CustomProvider 2. 在silo中註入代替預設實現 3. 在grain類上啟用 三丶運行結果如下 示例代碼下載地址:SimpleStorage ...
  • string strguid = Guid.NewGuid().ToString();//57d99d89-caab-482a-a0e9-a0a803eed3ba 生成標準的標誌符 (36位標準)strguid = Guid.NewGuid().ToString("D");//57d99d89-ca ...
  • 目錄 獲取請求的參數 獲取完整的請求路徑 獲取功能變數名稱 編碼 文件上傳的保存方法 獲取物理路徑 返回Json屬性大小寫問題 webconfig的配置移植到appsettings.json 設置區域塊MVC的路由器和訪問區域塊的視圖 NetCore訪問靜態資源文件 MVC調用子頁視圖 過濾器 使用sess ...
  • 由於公司業務需要簡單的把代碼加密混淆,於是瞭解了一下相關的工具然後打算用ConfuserEx試試。 開源地址:https://github.com/yck1509/ConfuserEx/ 下載地址:https://github.com/yck1509/ConfuserEx/releases 開始工作 ...
  • 工欲善其事必先利其器,我們既然有Visual Studio2019這樣的IDE為什麼不用?學.Net Core而不用Visual Studio進行開發可謂是多麼另類呀!既然你已經安裝了VS2019的話我們就來創建一個MVC Web吧,如果你還不會安裝,可以看我之前發表的安裝教程,很簡單哦。之前講了命 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...