Angular 從入坑到挖坑 - 路由守衛連連看

来源:https://www.cnblogs.com/danvic712/archive/2020/06/03/getting-started-with-angular-route-guards.html
-Advertisement-
Play Games

一、Overview Angular 入坑記錄的筆記第六篇,介紹 Angular 路由模塊中關於路由守衛的相關知識點,瞭解常用到的路由守衛介面,知道如何通過實現路由守衛介面來實現特定的功能需求,以及實現對於特性模塊的惰性載入 對應官方文檔地址: 路由與導航 配套代碼地址:angular-practi ...


一、Overview

Angular 入坑記錄的筆記第六篇,介紹 Angular 路由模塊中關於路由守衛的相關知識點,瞭解常用到的路由守衛介面,知道如何通過實現路由守衛介面來實現特定的功能需求,以及實現對於特性模塊的惰性載入

對應官方文檔地址:

配套代碼地址:angular-practice/src/router-combat

二、Contents

  1. Angular 從入坑到棄坑 - Angular 使用入門
  2. Angular 從入坑到挖坑 - 組件食用指南
  3. Angular 從入坑到挖坑 - 表單控制項概覽
  4. Angular 從入坑到挖坑 - HTTP 請求概覽
  5. Angular 從入坑到挖坑 - Router 路由使用入門指北
  6. Angular 從入坑到挖坑 - 路由守衛連連看

三、Knowledge Graph

思維導圖

四、Step by Step

4.1、基礎準備

重覆上一篇筆記的內容,搭建一個包含路由配置的 Angualr 項目

新建四個組件,分別對應於三個實際使用到的頁面與一個設置為通配路由的 404 頁面

-- 危機中心頁面
ng g component crisis-list

-- 英雄中心頁面
ng g component hero-list

-- 英雄相親頁面
ng g component hero-detail

-- 404 頁面
ng g component page-not-found 

在 app-routing.module.ts 文件中完成對於項目路由的定義,這裡包含了對於路由的重定向、通配路由,以及通過動態路由進行參數傳遞的使用

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

// 引入組件
import { CrisisListComponent } from './crisis-list/crisis-list.component';
import { HeroListComponent } from './hero-list/hero-list.component';
import { HeroDetailComponent } from './hero-detail/hero-detail.component';
import { PageNotFoundComponent } from './page-not-found/page-not-found.component';

const routes: Routes = [
  {
    path: 'crisis-center',
    component: CrisisListComponent,
  },
  {
    path: 'heroes',
    component: HeroListComponent,
  },
  {
    path: 'hero/:id',
    component: HeroDetailComponent,
  },
  {
    path: '',
    redirectTo: '/heroes',
    pathMatch: 'full',
  },
  {
    path: '**',
    component: PageNotFoundComponent,
  }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule],
})
export class AppRoutingModule { }

之後,在根組件中,添加 router-outlet 標簽用來聲明路由在頁面上渲染的出口

<h1>Angular Router</h1>
<nav>
  <a routerLink="/crisis-center" routerLinkActive="active">Crisis Center</a> &nbsp;&nbsp;
  <a routerLink="/heroes" routerLinkActive="active">Heroes</a>
</nav>
<router-outlet></router-outlet>

項目初始化

4.2、路由守衛

在 Angular 中,路由守衛主要可以解決以下的問題

  • 對於用戶訪問頁面的許可權校驗(是否已經登錄?已經登錄的角色是否有許可權進入?)
  • 在跳轉到組件前獲取某些必須的數據
  • 離開頁面時,提示用戶是否保存未提交的修改

Angular 路由模塊提供瞭如下的幾個介面用來幫助我們解決上面的問題

  • CanActivate:用來處理系統跳轉到到某個路由地址的操作(判斷是否可以進行訪問)
  • CanActivateChild:功能同 CanActivate,只不過針對的是子路由
  • CanDeactivate:用來處理從當前路由離開的情況(判斷是否存在未提交的信息)
  • CanLoad:是否允許通過延遲載入的方式載入某個模塊

在添加了路由守衛之後,通過路由守衛返回的值,從而達到我們控制路由的目的

  • true:導航將會繼續
  • false:導航將會中斷,用戶停留在當前的頁面或者是跳轉到指定的頁面
  • UrlTree:取消當前的導航,並導航到路由守衛返回的這個 UrlTree 上(一個新的路由信息)
4.2.1、CanActivate:認證授權

在實現路由守衛之前,可以通過 Angular CLI 來生成路由守衛的介面實現類,通過命令行,在 app/auth 路徑下生成一個授權守衛類,CLI 會提示我們選擇繼承的路由守衛介面,這裡選擇 CanActivate 即可

ng g guard auth/auth

創建路由守衛實現類

在 AuthGuard 這個路由守衛類中,我們模擬了是否允許訪問一個路由地址的認證授權。首先判斷是否已經登錄,如果登錄後再判斷當前登錄人是否具有當前路由地址的訪問許可權

import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree, Router } from '@angular/router';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class AuthGuard implements CanActivate {

  /**
   * ctor
   * @param router 路由
   */
  constructor(private router: Router) { }

  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {

    // 判斷是否有 token 信息
    let token = localStorage.getItem('auth-token') || '';
    if (token === '') {
      this.router.navigate(['/login']);
      return false;
    }

    // 判斷是否可以訪問當前連接
    let url: string = state.url;
    if (token === 'admin' && url === '/crisis-center') {
      return true;
    }

    this.router.navigate(['/login']);
    return false;
  }
}

之後我們就可以在 app-routing.module.ts 文件中引入 AuthGuard 類,針對需要保護的路由進行路由守衛的配置

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

// 引入組件
import { CrisisListComponent } from './crisis-list/crisis-list.component';

// 引入路由守衛
import { AuthGuard } from './auth/auth.guard';

const routes: Routes = [
  {
    path: 'crisis-center',
    component: CrisisListComponent,
    canActivate: [AuthGuard], // 添加針對當前路由的 canActivate 路由守衛
  }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule],
})
export class AppRoutingModule { }

使用 CanActivate 進行路由的認證授權

4.2.2、CanActivateChild:針對子路由的認證授權

與繼承 CanActivate 介面進行路由守衛的方式相似,針對子路由的認證授權可以通過繼承 CanActivateChild 介面來實現,因為授權的邏輯很相似,這裡通過多重繼承的方式,擴展 AuthGuard 的功能,從而達到同時針對路由和子路由的路由守衛

改造下原先 canActivate 方法的實現,將認證邏輯修改為用戶的 token 信息中包含 admin 即可訪問 crisis-center 頁面,在針對子路由進行認證授權的 canActivateChild 方法中,通過判斷 token 信息是否為 admin-master 模擬完成對於子路由的訪問認證

import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree, Router, CanActivateChild } from '@angular/router';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class AuthGuard implements CanActivate, CanActivateChild {

  /**
   * ctor
   * @param router 路由
   */
  constructor(private router: Router) { }

  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {

    // 判斷是否有 token 信息
    let token = localStorage.getItem('auth-token') || '';
    if (token === '') {
      this.router.navigate(['/login']);
      return false;
    }

    // 判斷是否可以訪問當前連接
    let url: string = state.url;
    if (token.indexOf('admin') !== -1 && url.indexOf('/crisis-center') !== -1) {
      return true;
    }

    this.router.navigate(['/login']);
    return false;
  }

  canActivateChild(
    childRoute: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): boolean | UrlTree | Observable<boolean | UrlTree> | Promise<boolean | UrlTree> {
    let token = localStorage.getItem('auth-token') || '';
    if (token === '') {
      this.router.navigate(['/login']);
      return false;
    }

    return token === 'admin-master';
  }
}

通過 Angular CLI 新增一個 crisis-detail 組件,作為 crisis-list 的子組件

ng g component crisis-detail

接下來在 crisis-list 中添加 router-outlet 標簽,用來定義子路由的渲染出口

<h2>危機中心</h2>

<ul class="crises">
  <li *ngFor="let crisis of crisisList">
    <a [routerLink]="[crisis.id]">
      <span class="badge">{{ crisis.id }}</span>{{ crisis.name }}
    </a>
  </li>
</ul>

<!-- 定義子路由的渲染出口 -->
<router-outlet></router-outlet>

在針對子路由的認證授權配置時,我們可以選擇針對每個子路由添加 canActivateChild 屬性,也可以定義一個空地址的子路由,將所有歸屬於 crisis-list 的子路由作為這個空路由的子路由,通過針對這個空路徑添加 canActivateChild 屬性,從而實現將守護規則應用到所有的子路由上

這裡其實相當於將原先兩級的路由模式(父:crisis-list,子:crisis-detail)改成了三級(父:crisis-list,子:' '(空路徑),孫:crisis-detail)

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

// 引入組件
import { CrisisListComponent } from './crisis-list/crisis-list.component';
import { CrisisDetailComponent } from './crisis-detail/crisis-detail.component';

// 引入路由守衛
import { AuthGuard } from './auth/auth.guard';

const routes: Routes = [
  {
    path: 'crisis-center',
    component: CrisisListComponent,
    canActivate: [AuthGuard], // 添加針對當前路由的 canActivate 路由守衛
    children: [{
      path: '',
      canActivateChild: [AuthGuard], // 添加針對子路由的 canActivate 路由守衛
      children: [{
        path: 'detail',
        component: CrisisDetailComponent
      }]
    }]
  }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule],
})
export class AppRoutingModule { }

使用 CanActivateChild 完成對於子路由的認證授權

4.2.3、CanDeactivate:處理用戶未提交的修改

當進行表單填報之類的操作時,因為會涉及到一個提交的動作,當用戶沒有點擊保存按鈕就離開時,最好能暫停,對用戶進行一個友好性的提示,由用戶選擇後續的操作

創建一個路由守衛,繼承於 CanDeactivate 介面

ng g guard hero-list/guards/hero-can-deactivate

與上面的 CanActivate、CanActivateChild 路由守衛的使用方式不同,對於 CanDeactivate 守衛來說,我們需要將參數中的 unknown 替換成我們實際需要進行路由守衛的組件

import { Injectable } from '@angular/core';
import { CanDeactivate, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree } from '@angular/router';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class HeroCanDeactivateGuard implements CanDeactivate<unknown> {
  canDeactivate(
    component: unknown,
    currentRoute: ActivatedRouteSnapshot,
    currentState: RouterStateSnapshot,
    nextState?: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
    return true;
  }
  
}

例如,這裡針對的是 HeroListComponent 這個組件,因此我們需要將泛型的參數 unknown 改為 HeroListComponent,通過 component 參數,就可以獲得需要進行路由守衛的組件的相關信息

import { Injectable } from '@angular/core';
import {
  CanDeactivate,
  ActivatedRouteSnapshot,
  RouterStateSnapshot,
  UrlTree,
} from '@angular/router';
import { Observable } from 'rxjs';

// 引入需要進行路由守衛的組件
import { HeroListComponent } from '../hero-list.component';

@Injectable({
  providedIn: 'root',
})
export class HeroCanDeactivateGuard
  implements CanDeactivate<HeroListComponent> {
  canDeactivate(
    component: HeroListComponent,
    currentRoute: ActivatedRouteSnapshot,
    currentState: RouterStateSnapshot,
    nextState?: RouterStateSnapshot
  ):
    | Observable<boolean | UrlTree>
    | Promise<boolean | UrlTree>
    | boolean
    | UrlTree {

    // 判斷是否修改了原始數據
    //
    const data = component.hero;
    if (data === undefined) {
      return true;
    }
    const origin = component.heroList.find(hero => hero.id === data.id);
    if (data.name === origin.name) {
      return true;
    }

    return window.confirm('內容未提交,確認離開?');
  }
}

這裡模擬判斷用戶有沒有修改原始的數據,當用戶修改了數據並移動到別的頁面時,觸發路由守衛,提示用戶是否保存後再離開當前頁面

使用 CanDeactivate 處理用戶未提交的修改

4.3、非同步路由

4.3.1、惰性載入

當應用逐漸擴大,使用現有的載入方式會造成應用在第一次訪問時就載入了全部的組件,從而導致系統首次渲染過慢。因此這裡可以使用惰性載入的方式在請求具體的模塊時才載入對應的組件

惰性載入只針對於特性模塊(NgModule),因此為了使用惰性載入這個功能點,我們需要將系統按照功能劃分,拆分出一個個獨立的模塊

首先通過 Angular CLI 創建一個危機中心模塊(crisis 模塊)

-- 查看創建模塊的相關參數
ng g module --help

-- 創建危機中心模塊(自動在 app.moudule.ts 中引入新創建的 CrisisModule、添加當前模塊的路由配置)
ng g module crisis --module app --routing

將 crisis-list、crisis-detail 組件全部移動到 crisis 模塊下麵,併在 CrisisModule 中添加對於 crisis-list、crisis-detail 組件的聲明,同時將原來在 app.module.ts 中聲明的組件代碼移除

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';

import { CrisisRoutingModule } from './crisis-routing.module';

import { FormsModule } from '@angular/forms';

// 引入模塊中使用到的組件
import { CrisisListComponent } from './crisis-list/crisis-list.component';
import { CrisisDetailComponent } from './crisis-detail/crisis-detail.component';


@NgModule({
  declarations: [
    CrisisListComponent,
    CrisisDetailComponent
  ],
  imports: [
    CommonModule,
    FormsModule,
    CrisisRoutingModule
  ]
})
export class CrisisModule { }

同樣的,將當前模塊的路由配置移動到專門的路由配置文件 crisis-routing.module.ts 中,並將 app-routing.module.ts 中相關的路由配置刪除

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

// 引入組件
import { CrisisListComponent } from './crisis-list/crisis-list.component';
import { CrisisDetailComponent } from './crisis-detail/crisis-detail.component';

// 引入路由守衛
import { AuthGuard } from '../auth/auth.guard';

const routes: Routes = [{
  path: '',
  component: CrisisListComponent,
  canActivate: [AuthGuard], // 添加針對當前路由的 canActivate 路由守衛
  children: [{
    path: '',
    canActivateChild: [AuthGuard], // 添加針對子路由的 canActivate 路由守衛
    children: [{
      path: 'detail',
      component: CrisisDetailComponent
    }]
  }]
}];

@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule]
})
export class CrisisRoutingModule { }

重新運行項目,如果你在創建模塊的命令中設置了自動引入當前模塊到 app.module.ts 文件中,大概率會遇到下麵的問題

創建特性模塊

這裡的問題與配置通配路由需要放到最後的原因相似,因為腳手架在幫我們將創建的模塊導入到 app.module.ts 中時,是添加到整個數組的最後,同時因為我們已經將 crisis 模塊的路由配置移動到專門的 crisis-routing.module.ts 中了,框架在進行路由匹配時會預先匹配上 app-routing.module.ts 中設置的通配路由,從而導致無法找到實際應該對應的組件,因此這裡我們需要將 AppRoutingModule 放到聲明的最後

app.module.ts

當問題解決後,就可以針對 crisis 模塊設置惰性載入

在配置惰性路由時,我們需要以一種類似於子路由的方式進行配置,通過路由的 loadChildren 屬性來載入對應的模塊,而不是具體的組件,修改後的 AppRoutingModule 代碼如下

import { HeroCanDeactivateGuard } from './hero-list/guards/hero-can-deactivate.guard';
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

const routes: Routes = [
  {
    path: 'crisis-center',
    loadChildren: () => import('./crisis/crisis.module').then(m => m.CrisisModule)
  }
];

@NgModule({
  imports: [RouterModule.forRoot(routes, { enableTracing: true })],
  exports: [RouterModule],
})
export class AppRoutingModule { }

當導航到這個 /crisis-center 路由時,框架會通過 loadChildren 字元串來動態載入 CrisisModule,然後把 CrisisModule 添加到當前的路由配置中,而惰性載入和重新配置工作只會發生一次,也就是在該路由首次被請求時執行,在後續請求時,該模塊和路由都是立即可用的

4.3.2、CanLoad:杜絕未通過認證授權的組件載入

在上面的代碼中,對於 CrisisModule 模塊我們已經使用 CanActivate、CanActivateChild 路由守衛來進行路由的認證授權,但是當我們並沒有許可權訪問該路由的許可權,卻依然點擊了鏈接時,此時框架路由仍會載入該模塊。為了杜絕這種授權未通過仍載入模塊的問題發生,這裡需要使用到 CanLoad 守衛

因為這裡的判斷邏輯與認證授權的邏輯相同,因此在 AuthGuard 中,繼承 CanLoad 介面即可,修改後的 AuthGuard 代碼如下

import { Injectable } from '@angular/core';
import {
  CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree, Router, CanActivateChild, CanLoad, Route, UrlSegment
} from '@angular/router';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class AuthGuard implements CanActivate, CanActivateChild, CanLoad {

  /**
   * ctor
   * @param router 路由
   */
  constructor(private router: Router) { }


  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {

    // 判斷是否有 token 信息
    let token = localStorage.getItem('auth-token') || '';
    if (token === '') {
      this.router.navigate(['/login']);
      return false;
    }

    // 判斷是否可以訪問當前連接
    let url: string = state.url;
    if (token.indexOf('admin') !== -1 && url.indexOf('/crisis-center') !== -1) {
      return true;
    }

    this.router.navigate(['/login']);
    return false;
  }

  canActivateChild(
    childRoute: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): boolean | UrlTree | Observable<boolean | UrlTree> | Promise<boolean | UrlTree> {
    let token = localStorage.getItem('auth-token') || '';
    if (token === '') {
      this.router.navigate(['/login']);
      return false;
    }

    return token === 'admin-master';
  }

  canLoad(route: Route, segments: UrlSegment[]): boolean | Observable<boolean> | Promise<boolean> {
    let token = localStorage.getItem('auth-token') || '';
    if (token === '') {
      this.router.navigate(['/login']);
      return false;
    }

    let url = `/${route.path}`;

    if (token.indexOf('admin') !== -1 && url.indexOf('/crisis-center') !== -1) {
      return true;
    }
  }
}

同樣的,針對路由守衛的實現完成後,將需要使用到的路由守衛添加到 crisis-center 路由的 canLoad 數組中即可實現授權認證不通過時不載入模塊

import { HeroCanDeactivateGuard } from './hero-list/guards/hero-can-deactivate.guard';
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

const routes: Routes = [
  {
    path: 'crisis-center',
    loadChildren: () => import('./crisis/crisis.module').then(m => m.CrisisModule)
  }
];

@NgModule({
  imports: [RouterModule.forRoot(routes, { enableTracing: true })],
  exports: [RouterModule],
})
export class AppRoutingModule { }

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

-Advertisement-
Play Games
更多相關文章
  • 據官網介紹這個電子錶格插件,是一款純前端類似excel的線上表格,功能強大、配置簡單、完全開源. 官網鏈接: Luckysheet官網 線上DEMO 特性包含: 表格設置,包括凍結行列、合併單元格、篩選、排序、查詢、條件格式、批註; 支持數據分析功能包括透視表、分列、矩陣操作、內置385個計算函數; ...
  • 三角形 利用border-color支持transparent這一特性,隱藏三條邊框,實現三角形。 <style> .triangle { width: 0; height: 0; border-style: solid; box-sizing: border-box; border-width: ...
  • 前言 瀑布流佈局是前端領域中一個很常見的需求,由於圖片的高度是不一致的,所以在多列佈局中預設佈局下很難獲得滿意的排列。 我們的需求是,圖片高度不規律的情況下,在兩列佈局中,讓左右兩側的圖片總高度儘可能的接近,這樣的佈局會非常的美觀。 註意,本文的目的僅僅是討論演算法在前端中能如何運用,而不是說瀑布流的 ...
  • 首先簡單介紹下自己,目前七年前端實際項目經驗,有一線大廠經驗,也去過國外。算的上是前端老鳥了,這篇文章是個人的經驗和心得,不吹不黑,中肯的態度來說,希望能夠幫到大家。 都2020年了,我現在學前端還來的及麽? 這是很多前端新人經常問我的一個問題,有學弟學妹,也有想轉行的朋友。 我的意識里,“大前端時 ...
  • this是我們在書寫代碼時最常用的關鍵詞之一,即使如此,它也是JavaScript最容易被最頭疼的關鍵詞。那麼this到底是什麼呢? 如果你瞭解執行上下文,那麼你就會知道,其實this是執行上下文對象的一個屬性: executionContext = { scopeChain:[ ... ], VO ...
  • 以下只是其中一種方法: .figure { height: 1400px; width: calc(100% - 200px); background: white; float: left; } .figure_side { height: 1400px; width: 200px; backgr ...
  • 以下只是其中一種方法: .left { height: 1600px; width: 300px; background: rgb(235,235,235); float: left; } .middle { height: 1600px; background: skyblue; margin-l ...
  • 登高遠眺 滄海拾遺,積跬步以至千里 基礎技術 StackOverFlow 2020 年開發者報告 技術問答社區 StackOverFlow 的年度報告,本次報告統計了來自於全球各地共 65000 名開發者。有幾項數據令人震驚: 2020 年 jQuery 仍然是最受歡迎的 Web 開發者框架; Ru ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...