整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

ThinkPHP5.0.23源码分析系列(一):生命

ThinkPHP5.0.23婧愮爜鍒嗘瀽绯诲垪锛堜竴锛夛細鐢熷懡鍛ㄦ湡

銆佺敓鍛藉懆鏈燂細

浜屻€佸叆鍙f枃浠?/strong>

thinkphp浣跨敤鍗曚竴鍏ュ彛锛屾墍鏈夌殑璇锋眰閮戒粠榛樿鐨刬ndex.php鏂囦欢杩涘叆銆備綘杩樺彲浠ュ垱寤哄涓簲鐢紝涓€涓簲鐢ㄥ搴斾竴涓叆鍙f枃浠讹紝鎵€鏈夌殑鍏ュ彛鏂囦欢閮藉紩鐢ㄤ竴濂梩hinkphp绫诲簱銆?/p>

// 瀹氫箟搴旂敤鐩綍
define('APP_PATH', __DIR__ . '/../application/');
// 鍔犺浇妗嗘灦寮曞鏂囦欢
require __DIR__ . '/../thinkphp/start.php';

绗竴琛屼唬鐮?瀹氫箟浜嗗簲鐢ㄧ殑榛樿鐩綍锛?/p>

绗簩琛屼唬鐮佹槸鎴戜滑涓嬮潰瑕佺湅鐨勫紩瀵兼枃浠?/p>

娉ㄦ剰锛氬畼鏂逛笉寤鸿鍦ㄥ簲鐢ㄥ叆鍙f枃浠朵腑鍔犲叆杩囧鐨勪唬鐮侊紝灏ゅ叾鏄拰涓氬姟閫昏緫鐩稿叧鐨勪唬鐮併€?/p>

涓夈€佸紩瀵兼枃浠?/strong>

start.php鏂囦欢灏辨槸绯荤粺榛樿鐨勪竴涓紩瀵兼枃浠躲€傚湪寮曞鏂囦欢涓紝浼氫緷娆℃墽琛屼笅闈㈡搷浣滐細

鍔犺浇绯荤粺甯搁噺瀹氫箟-->鍔犺浇鐜鍙橀噺瀹氫箟鏂囦欢-->娉ㄥ唽鑷姩鍔犺浇鏈哄埗-->娉ㄥ唽閿欒鍜屽紓甯稿鐞嗘満鍒?->鍔犺浇鎯緥閰嶇疆鏂囦欢-->鎵ц搴旂敤

// ThinkPHP 寮曞鏂囦欢
// 1. 鍔犺浇鍩虹鏂囦欢
require __DIR__ . '/base.php';
// 2. 鎵ц搴旂敤
App::run()->send();

start.php寮曞鏂囦欢棣栧厛浼氳皟鐢╞ase.php鍩虹寮曞鏂囦欢锛屾煇浜涚壒娈婇渶姹備笅闈㈠彲鑳界洿鎺ュ湪鍏ュ彛鏂囦欢涓紩鍏ュ熀纭€寮曞鏂囦欢銆?/p>

鏂囩簿閫?NET Swagger 浣跨敤

鉂?/span>

鍦ㄥ悗绔紑鍙戜腑,甯哥敤 Web API 妯″紡,瀵瑰鎻愪緵 RESTful API 璁╁墠绔皟鐢?鑰屽叾涓渶钁楀悕鐨勫氨鏄娇鐢?Swagger(淇楃О:涓濊鍝?,Swagger 涓嶄絾鎻愪緵浜嗛潪甯哥洿瑙傜殑椤甸潰渚涘紑鍙戣€呮煡鐪?杩樿兘閰嶇疆娉ㄩ噴璇存槑,鍒嗙粍绛?杩樺彲浠ョ洿鎺ュ湪娴忚鍣ㄤ笂娴嬭瘯鎺ュ彛,鍙互璇存槸,鐜板湪涓嶇敤 Swagger 鐨勫悗绔紑鍙戣€呬笉鏄釜濂藉紑鍙戣€?鏈枃灏嗛拡瀵规垜鍦ㄦ棩甯稿伐浣滀腑浣跨敤 Swagger 鐨勪竴浜涙€荤粨鍜屼緥瀛?鍩烘湰涓婂睘浜庡鍒朵唬鐮佸氨鑳界敤.

鉂?/span>
  • 鏈枃榛樿澶у閮芥湁鐐瑰熀纭€,鑷冲皯浣跨敤 VS 鍒涘缓椤圭洰杩欎簺涓嶇敤鎴戝啀澶氳.
  • 鏈枃鐨勪緥瀛愪娇鐢ㄥ井杞粯璁ょ殑 Web API 妯℃澘杩涜鏋勫缓,浼氳缁嗙殑璁茶В姣忎竴姝?骞朵笖浼氬皢浠g爜涓婁紶鍒?GitHub.
  • 鏈枃浼氫粙缁?Swagger 鐨勬敞閲?鎺ュ彛鍒嗙粍,闅愯棌鎺ュ彛,浠ュ強缁欓渶瑕佹巿鏉冪殑鎺ュ彛娣诲姞鏍囪瘑.浠ュ強鍙楁敮鎸佺殑鏁版嵁绫诲瀷鐨勯粯璁ゅ€兼樉绀?
    • 娉ㄩ噴涓嶇敤璇?灏辨槸灏嗕唬鐮佹敞閲婃樉绀哄埌椤甸潰涓?
    • 鎺ュ彛鍒嗙粍鍙互瀹炵幇灏嗕笉鍚屽姛鑳界殑鎺у埗鍣ㄥ垎鍒颁笉鍚岀殑缁勪腑,渚夸簬鏌ョ湅.
    • 闅愯棌鎺ュ彛鍒欐槸灏嗕笉甯屾湜瀵瑰鍏紑鐨勬帴鍙d笉鏄剧ず,閴存潈鎺ュ彛鏍囪瘑鍒欐槸鍦?API 鐨勫悗杈规樉绀轰竴涓?馃敀 閿佸浘鏍?
    • 鏄剧ず榛樿鍊煎垯鏄湪鏌愪簺鏁版嵁涓?姣斿鐢ㄦ埛骞撮緞,榛樿鏄剧ず 20,鍓嶇涓€鐪嬪氨鐭ラ亾杩欐槸涓粈涔堟暟鎹被鍨?褰撶劧杩欓噷鐨勪緥瀛愪笉澶伆褰?鍙嶆鎰忔€濆樊涓嶅.
  • 鏈€缁堝憟鐜扮殑鏁堟灉澶ф灏辨槸濡備笅,鎺ヤ笅鏉ュ氨寮€濮嬩娇鐢ㄤ唬鐮佽鏄庤繖涓€鍒?

  • 棣栧厛浣跨敤 VS 鍒涘缓涓€涓?Web API 椤圭洰,杩欓噷鎴戝彨浠?Swagger.Sample,浣犱篃鍙互鍙粬鍏朵粬鍚嶅瓧,闅忎綘鑷繁.
  • 榛樿鐨?AddSwaggerGen 閰嶇疆浠g爜閲屼粈涔堥兘娌℃湁,鎵€浠ユ病鏈変粈涔堢壒娈婄殑鏁堟灉.浠呬粎鍙兘鏌ョ湅鎺ュ彛鍜岃皟璇曡€屽凡.
var builder=WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
// 閰嶇疆Swagger
builder.Services.AddSwaggerGen();
var app=builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseAuthorization();
app.MapControllers();
app.Run();
  • 鐢变簬榛樿浠g爜閲屾湁涓ぉ姘旀暟鎹帴鍙?鎴戜滑骞朵笉闇€瑕?鎵€浠ュ垹鎺変粬浠?骞舵坊鍔犲嚑涓?POST,PUT,GET,DELETE 绛夋帴鍙f潵鍋氫緥瀛?鎵€鏈夌殑鎺ュ彛鍧囪繑鍥炰竴涓瓧绗︿覆.鍙傛暟鏍规嵁涓嶅悓鐨勬帴鍙g被鍨?浼氬0鏄庝笉鍚岀殑鍙傛暟.浣嗘槸閮戒笉浼氬お澶嶆潅,澶у鑲畾閮借兘鎳?
  • 灏嗛粯璁ょ殑鎺у埗鍣ㄦ敼鎴愬涓嬭繖涓牱瀛?
using Microsoft.AspNetCore.Mvc;

// ReSharper disable ClassNeverInstantiated.Global

namespace Swagger.Sample.Controllers;

/// <summary>
/// 绗竴涓帶鍒跺櫒
/// </summary>
[ApiController, Route("[controller]/[action]")]
public class FirstController : ControllerBase
{
/// <summary>
/// Hello {name}
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
[HttpGet]
public string Hello(string name)=> $"Hello {name}";

/// <summary>
/// Hello World
/// </summary>
/// <returns></returns>
[HttpGet]
public string HelloWorld()=> "Hello World";

/// <summary>
/// PostOne
/// </summary>
/// <param name="parameter"></param>
/// <returns></returns>
[HttpPost]
public PostParameter PostOne(PostParameter parameter)=> parameter;

/// <summary>
/// PutOne
/// </summary>
/// <param name="id"></param>
/// <param name="put"></param>
/// <returns></returns>
[HttpPut("{id}")]
public string PutOne(string id, PutParameter put)=> $"update:{id},{put.Gender}";

/// <summary>
/// DeleteOne
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpDelete("{id}")]
public string DeleteOne(string id)=> $"delete {id}";
}

/// <summary>
/// Put鍙傛暟妯℃嫙
/// </summary>
public class PutParameter
{
/// <summary>
/// Gender
/// </summary>
public EGender Gender { get; set; }
}

/// <summary>
/// POST鍙傛暟妯℃嫙
/// </summary>
public class PostParameter : PutParameter
{
/// <summary>
/// Name
/// </summary>
public string Name { get; set; }=string.Empty;

/// <summary>
/// Age
/// </summary>
public int Age { get; set; }
}

/// <summary>
/// 鎬у埆鏋氫妇
/// </summary>
public enum EGender
{
/// <summary>
/// 鐢?/span>
/// </summary>
鐢?

/// <summary>
/// 濂?/span>
/// </summary>
濂?br>}
  • 涓婅竟鎼炰簡鍑犱釜渚嬪瓙.鍚姩鍚庝細鍙戠幇鎸夌収棰勬湡鏄剧ず椤甸潰.浣嗘槸娌℃湁娉ㄩ噴涔熸病鏈変笂杩板埆鐨勫姛鑳?

娣诲姞鏂囨。娉ㄩ噴

  • 瑕佽 Swagger 鏄剧ず鏂囨。娉ㄩ噴,棣栧厛瑕佸椤圭洰娣诲姞 XML 鏂囨。鐢熸垚.
  • 鎵撳紑椤圭洰鐨?xxx.csproj 鎴戣繖閲屾槸 Swagger.Sample.csproj,鍦?PropertyGroup 鑺傜偣涓嬫坊鍔?GenerateDocumentationFile 涓?Trune 濡備笅鍐呭:
 <PropertyGroup>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
</PropertyGroup>
  • 杩欐椂鍊欏惎鍔ㄩ」鐩?铏界劧浼氱敓鎴愮浉搴旂殑鏂囦欢,浣嗘槸 Swagger 杩樻槸鏃犳硶姝e父鏄剧ず娉ㄩ噴,鍏跺師鍥犲氨鏄皻鏈 Swaager 杩涜閰嶇疆,杩欓噷鎴戜滑鍏堟潵娣诲姞鏂囨。娉ㄩ噴鏄剧ず.
  • 鎵撳紑 Program.cs 鏂囦欢.鑻ユ槸杩涜杩囧皝瑁?鍙兘浼氭槸鍏朵粬鏂囦欢,杩欓噷涓嶅仛鎺㈣,鎴戜滑鍏ㄩ儴閮藉湪 Program.cs 涓繘琛?
  • 鎴戜滑灏嗕唬鐮佹敼鎴愬涓嬪舰寮?/section>
var builder=WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
// 閰嶇疆Swagger
builder.Services.AddSwaggerGen(c=>
{
// 濉啓鏂囨。鐨勪竴浜涘睘鎬?鍚嶇О,鐗堟湰鍜屾弿杩颁俊鎭?/span>
c.SwaggerDoc("Swagger.Sample", new()
{
Title="Swagger.Sample",
Version="v1",
Description="Console.WriteLine(\"馃悅馃嵑\")"
});
// 鎵惧埌绋嬪簭杩愯鐩綍涓嬬殑鎵€鏈墄ml鏂囦欢
var files=Directory.GetFiles(AppContext.BaseDirectory, "*.xml");
foreach (var file in files)
{
// 閰嶇疆娉ㄩ噴鏂囨。
c.IncludeXmlComments(file, true);
}
});
var app=builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI(c=> c.SwaggerEndpoint("/swagger/Swagger.Sample/swagger.json", "Swagger.Sample v1"));
}
app.UseAuthorization();
app.MapControllers();
app.Run();
  • 鍙鎴戜滑鍦?AddSwaggerGen 鍜?UseSwaggerUI 涓兘娣诲姞浜嗕竴浜涢厤缃?璁?Swagger 鍙互鎵惧埌瀵瑰簲鐨?XML 娉ㄩ噴鏂囦欢,杩欐椂鍊欏啀閲嶆柊杩愯绋嬪簭,鍗冲彲鐪嬪埌娉ㄩ噴浜?
  • 杩欓噷鐨勯厤缃垜浠彲浠ョ湅鍒?涓嶇鏄枃妗g殑鍚嶇О杩樻槸 swagger.json 鏂囦欢璺緞鍧囨槸纭紪鐮佺殑,杩欐柟闈㈠悗杈圭殑璋冩暣涓細閫愭璋冩暣,杩欓噷鍏堜笉鐢ㄥ湪鎰?

  • 鍒拌繖閲屾敞閲婂氨鍩烘湰娣诲姞瀹屾垚,鍘熺悊涔熸噦浜?

鏂囨。鍒嗙粍

  • 鎺ュ彛鏂囨。鍒嗙粍鎴戣繖閲屼娇鐢ㄤ簡涓€浜涚壒鎬?閰嶅悎鍙嶅皠鏉ヨ幏鍙栧垎缁勪俊鎭?鎵€浠ユ垜浠渶瑕佸厛鍒涘缓涓€涓伐鍏风被鏉ュ府鍔╂垜浠柟渚夸娇鐢ㄥ弽灏?
  • 鍒涘缓涓€涓?Tool 鏂囦欢澶?鐢ㄦ潵鏀句竴浜涙墿灞曠被.骞舵柊寤烘垜浠殑绗竴涓?杩欎釜渚嬪瓙閲屽簲璇ヤ篃鏄渶鍚庝竴涓?鎵╁睍绫?AssemblyHelper.cs,骞舵坊鍔犲涓嬩唬鐮?
using Microsoft.Extensions.DependencyModel;
using System.Reflection;
using System.Runtime.Loader;

namespace Swagger.Sample.Tools;

/// <summary>
/// 绋嬪簭闆嗗府鍔╃被
/// </summary>
// ReSharper disable once UnusedType.Global
public static class AssemblyHelper
{
private static readonly string[] Filters={ "dotnet-", "Microsoft.", "mscorlib", "netstandard", "System", "Windows" };
private static readonly IEnumerable<Assembly>? _allAssemblies;
private static readonly IEnumerable<Type>? _allTypes;

/// <summary>
/// 闇€瑕佹帓闄ょ殑椤圭洰
/// </summary>
private static readonly List<string> FilterLibs=new();

/// <summary>
/// 鏋勯€犲嚱鏁?/span>
/// </summary>
static AssemblyHelper()
{
_allAssemblies=DependencyContext.Default?.GetDefaultAssemblyNames().Where(c=> c.Name is not && !Filters.Any(c.Name.StartsWith) && !FilterLibs.Any(c.Name.StartsWith)).Select(Assembly.Load);
_allTypes=_allAssemblies?.SelectMany(c=> c.GetTypes());
}

/// <summary>
/// 娣诲姞鎺掗櫎椤圭洰,璇ユ帓闄ら」鐩彲鑳戒細褰卞搷AutoDependenceInjection鑷姩娉ㄥ叆,璇蜂娇鐢ㄧ殑鏃跺€欒嚜琛屾祴璇?
/// </summary>
/// <param name="names"></param>
public static void AddExcludeLibs(params string[] names)=> FilterLibs.AddRangeIfNotContains(names);

/// <summary>
/// 鏍规嵁绋嬪簭闆嗗悕瀛楀緱鍒扮▼搴忛泦
/// </summary>
/// <param name="assemblyNames"></param>
/// <returns></returns>
public static IEnumerable<Assembly> GetAssembliesByName(params string[] assemblyNames)=> assemblyNames.Select(o=> AssemblyLoadContext.Default.LoadFromAssemblyPath(Path.Combine(AppContext.BaseDirectory, $"{o}.dll")));

/// <summary>
/// 鏌ユ壘鎸囧畾鏉′欢鐨勭被鍨?/span>
/// </summary>
public static IEnumerable<Type> FindTypes(Func<Type, bool> predicate)=> _allTypes!.Where(predicate).ToArray();

/// <summary>
/// 鏌ユ壘鎵€鏈夋寚瀹氱壒鎬ф爣璁扮殑绫诲瀷
/// </summary>
/// <typeparam name="TAttribute"></typeparam>
/// <returns></returns>
public static IEnumerable<Type> FindTypesByAttribute<TAttribute>() where TAttribute : Attribute=> FindTypesByAttribute(typeof(TAttribute));

/// <summary>
/// 鏌ユ壘鎵€鏈夋寚瀹氱壒鎬ф爣璁扮殑绫诲瀷
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public static IEnumerable<Type> FindTypesByAttribute(Type type)=> _allTypes!.Where(a=> a.IsDefined(type, true)).Distinct().ToArray();

/// <summary>
/// 鏌ユ壘鎸囧畾鏉′欢鐨勭被鍨?/span>
/// </summary>
public static IEnumerable<Assembly> FindAllItems(Func<Assembly, bool> predicate)=> _allAssemblies!.Where(predicate).ToArray();

/// <summary>
/// 娣诲姞涓嶉噸澶嶇殑鍏冪礌
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="this"></param>
/// <param name="values"></param>
private static void AddRangeIfNotContains<T>(this ICollection<T> @this, params T[] values)
{
foreach (var obj in values)
{
if (@this.Contains(obj)) continue;
@this.Add(obj);
}
}
}
  • 鍐欏ソ甯姪绫诲悗,鍗冲彲鏂板缓涓€涓壒鎬х敤鏉ユ壙杞芥垜浠殑鍒嗙粍淇℃伅.
  • 鏂板缓涓€涓枃浠跺す Attributes 骞舵坊鍔?ApiGroupAttribute.cs,骞跺啓鍏ュ涓嬩唬鐮?
namespace Swagger.Sample.Attributes;

/// <summary>
/// 琚鐗规€ф爣璁扮殑鎺у埗鍣ㄥ彲鍦⊿wagger鏂囨。鍒嗙粍涓彂鎸ヤ綔鐢?
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
// ReSharper disable once UnusedMember.Global
// ReSharper disable once UnusedType.Global
// ReSharper disable once ClassNeverInstantiated.Global
public sealed class ApiGroupAttribute : Attribute
{
/// <summary>
/// 鏋勯€犲嚱鏁?/span>
/// </summary>
/// <param name="title"></param>
/// <param name="version"></param>
/// <param name="description"></param>
public ApiGroupAttribute(string title, string version, string description="")
{
Title=title;
Version=version;
Description=description;
Name=$"{title}-{version}";
}

/// <summary>
/// Doc鍚嶇О,$"{Title}-{Version}"鏍煎紡
/// </summary>
public string Name { get; }

/// <summary>
/// 鏍囬
/// </summary>
public string Title { get; }

/// <summary>
/// 鐗堟湰
/// </summary>
public string Version { get; }

/// <summary>
/// 鎻忚堪
/// </summary>
public string Description { get; }
}
  • 鍏朵腑鍚勪釜瀛楁鐨勫惈涔?鍧囨湁娉ㄩ噴.鏂逛究鐞嗚В.杩欎釜鏃跺€欐垜浠噯澶囧伐浣滃氨鍋氬ソ浜?鍙互寮€濮嬫敼閫?Programe.cs 涓殑閰嶇疆浜?
  • 棣栧厛鍒涘缓鍑犱釜灞€閮ㄥ彉閲?鐢ㄦ潵瀛樺偍涓€浜涗俊鎭?
// 鏂囨。鏍囬
const string Title="Test"; // 鏂囨。鏍囬
const string Version="v1"; // 鐗堟湰
const string Name=$"{Title}-{Version}"; // 鏂囨。鍚嶇О
Dictionary<string, string> docsDic=new(); // 鐢ㄦ潵瀛樺偍鏂囨。鍒嗙粍鐨勪俊鎭?/span>
Dictionary<string, string> endPointDic=new(); // 瀛樺偍鏂囨。缁堢粨鐐筳son淇℃伅
  • 鐒跺悗淇敼 AddSwaggerGen 鍜?UseSwaggerUI 涓哄涓嬪唴瀹?
  • 涓轰簡鏂逛究,鍚庢湡鍧囦細灞曠ず瀹屾暣鐨?Programe.cs 浠g爜
using Swagger.Sample.Attributes;
using Swagger.Sample.Tools;
using System.Reflection;

var builder=WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();

// 閰嶇疆Swagger
const string Title="Test"; // 鏂囨。鏍囬
const string Version="v1"; // 鐗堟湰
const string Name=$"{Title}-{Version}"; // 鏂囨。鍚嶇О
Dictionary<string, string> docsDic=new(); // 鐢ㄦ潵瀛樺偍鏂囨。鍒嗙粍鐨勪俊鎭?/span>
Dictionary<string, string> endPointDic=new(); // 瀛樺偍鏂囨。缁堢粨鐐筳son淇℃伅
builder.Services.AddSwaggerGen(c=>
{
// 閰嶇疆榛樿鍒嗙粍
c.SwaggerDoc(Name, new()
{
Title=Title,
Version=Version,
Description="Console.WriteLine(\"馃悅馃嵑\")"
});
// 閰嶇疆鏂囨。娉ㄩ噴
var files=Directory.GetFiles(AppContext.BaseDirectory, "*.xml");
foreach (var file in files)
{
c.IncludeXmlComments(file, true);
}
// 鑾峰彇鎺у埗鍣ㄥ垎缁勪俊鎭拰閰嶇疆鍒嗙粍
var controllers=AssemblyHelper.FindTypesByAttribute<ApiGroupAttribute>();
foreach (var ctrl in controllers)
{
var attr=ctrl.GetCustomAttribute<ApiGroupAttribute>();
if (attr is ) continue;
if (docsDic.ContainsKey(attr.Name)) continue;
_=docsDic.TryAdd(attr.Name, attr.Description);
c.SwaggerDoc(attr.Name, new()
{
Title=attr.Title,
Version=attr.Version,
Description=attr.Description
});
}
c.DocInclusionPredicate((docName, apiDescription)=>
{
//鍙嶅皠鎷垮埌鍊?/span>
var actionList=apiDescription.ActionDescriptor.EndpointMetadata.Where(x=> x is ApiGroupAttribute).ToList();
if (actionList.Count !=0)
{
return actionList.FirstOrDefault() is ApiGroupAttribute attr && attr.Name==docName;
}
//鍒ゆ柇鏄惁鍖呭惈杩欎釜鍒嗙粍
var not=apiDescription.ActionDescriptor.EndpointMetadata.Where(x=> x is not ApiGroupAttribute).ToList();
return not.Count !=0 && docName==Name;
});
});
var app=builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI(c=>
{
// 榛樿鍒嗙粍
c.SwaggerEndpoint($"/swagger/{Name}/swagger.json", $"{Title} {Version}");
// 閰嶇疆浣跨敤ApiGroupAttribute鐨勫垎缁?/span>
var controllers=AssemblyHelper.FindTypesByAttribute<ApiGroupAttribute>();
foreach (var ctrl in controllers)
{
var attr=ctrl.GetCustomAttribute<ApiGroupAttribute>();
if (attr is ) continue;
if (endPointDic.ContainsKey(attr.Name)) continue;
_=endPointDic.TryAdd(attr.Name, attr.Description);
c.SwaggerEndpoint($"/swagger/{attr.Name}/swagger.json", $"{attr.Title} {attr.Version}");
}
});
}
app.UseAuthorization();
app.MapControllers();
app.Run();
  • 杩欓噷鍒嗙粍鐨勯€昏緫浠g爜灏卞凡缁忓畬鎴愪簡,鎴戜滑鍐嶆柊寤?TwoController 鍜?ThreeController 鎺у埗鍣ㄦ潵婕旂ず鍒嗙粍.
/// <summary>
/// TwoController
/// </summary>
[Route("api/[controller]/[action]"), ApiController, ApiGroup("GroupOne", "v1", "绗竴涓垎缁?)]
public class TwoController : ControllerBase
{
/// <summary>
/// TwoHello
/// </summary>
/// <returns></returns>
[HttpGet]
public string TwoHello()=> "Hello GroupOne";
}

/// <summary>
/// ThreeController
/// </summary>
[Route("api/[controller]/[action]"), ApiController, ApiGroup("GroupOne", "v1", "绗竴涓垎缁?)]
public class ThreeController : ControllerBase
{
/// <summary>
/// ThreeHello
/// </summary>
/// <returns></returns>
[HttpGet]
public string ThreeHello()=> "Hello GroupOne";
}
  • 鍙互鐪嬪埌鎴戜滑鍒嗙粍鎴愬姛鍚?閫夋嫨 GroupOne 鍒嗙粍鍗冲彲鐪嬪埌 Two 鍜?Three 鎺у埗鍣ㄧ殑 API 浜?

涓烘坊鍔犱簡 Authorize 鐗规€х殑鎺ュ彛娣诲姞閿佸浘鏍?/span>

  • Authorize 涓?NET 妗嗘灦鑷甫鐨勪竴涓壒鎬?琚粬鏍囪鐨勬帴鍙?鍙互琛ㄧず璇ユ帴鍙i渶瑕乀oken鏍¢獙閫氳繃鎵嶈兘璁块棶.鎴戜滑鍙互浣跨敤 OpenApiSecurityScheme 鏉ヤ负鎺ュ彛娣诲姞閿?涓嶈繃杩欎釜鏂规鏈変釜缂虹偣,浼氭妸鎵€鏈夌殑鎺ュ彛鍧囧姞涓婇攣,鍏跺疄鎴戜滑瀹為檯寮€鍙戜腑鏈変簺鎺ュ彛鏄笉闇€瑕佺殑,铏界劧璁块棶鍙兘娌℃湁浠€涔堥棶棰?浣嗘槸杩欎細缁欏墠绔€犳垚涓€浜涜瑙?姣斿鐧诲綍鎺ュ彛鏈変釜閿?灏变細璁╀汉寰堟嚨 馃樀.涓轰簡閬垮厤杩欎簺涓嶅繀瑕佺殑璇В.鎵€浠ュ氨鏈変簡杩欎釜闇€姹?涓哄彧鏍囪浜?Authorize 鐗规€х殑 API 娣诲姞閿佸浘鏍?
  • 鍦ㄩ」鐩噷鏂板缓涓€涓枃浠跺す SwaggerFilters,瀛樻斁鎴戜滑鐨勮嚜瀹氫箟鐨勪竴浜涢拡瀵?Swagger 鐨?Filters.杩欓噷鎴戜滑鍏堝垱寤虹涓€涓?SwaggerAuthorizeFilter.cs,骞舵坊鍔犲涓嬩唬鐮?
/// <summary>
/// 鍦⊿wagger鏂囨。涓粰闇€瑕丄uthorize鐨勬帴鍙f坊鍔狆煍?/span>
/// </summary>
// ReSharper disable once UnusedMember.Global
// ReSharper disable once ClassNeverInstantiated.Global
public sealed class SwaggerAuthorizeFilter : IOperationFilter
{
/// <summary>
/// Apply
/// </summary>
/// <param name="operation"></param>
/// <param name="context"></param>
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
// 鍏堢瓫閫夊嚭鍖呭惈Authorize鐗规€х殑鎺ュ彛
var authAttributes=context.MethodInfo.DeclaringType?.GetCustomAttributes(true)
.Union(context.MethodInfo.GetCustomAttributes(true))
.OfType<AuthorizeAttribute>();
if (!authAttributes!.Any()) return;
// 鐒跺悗涓哄叾娣诲姞SecurityScheme
// 鐢变簬椤圭洰涓ぇ閮ㄥ垎浣跨敤鐨勯兘鏄痮auth2 Bearer Token璁よ瘉鎵€浠ヨ繖閲岄粯璁や互杩欑鏂瑰紡瀹炵幇.鍒殑鏂规璇疯嚜琛岃皟鏁?
operation.Security=new List<OpenApiSecurityRequirement>
{
new()
{
{
new()
{
Reference=new()
{
Type=ReferenceType.SecurityScheme,
Id="Bearer"
},
Scheme="oauth2",
Name="Bearer",
In=ParameterLocation.Header
},
new List<string>()
}
}
};
operation.Responses.Add("401", new() { Description="Unauthorized" });
}
}
  • 鍐欏ソ Fillter 鍚庝簨鎯呭氨绠€鍗曚簡.鍦?AddSwaggerGen 鏂规硶涓坊鍔犱竴琛屼唬鐮佸嵆鍙?
builder.Services.AddSwaggerGen(c=>
{
...
c.DocInclusionPredicate((docName, apiDescription)=>
{
...
});
c.OperationFilter<SwaggerAuthorizeFilter>(); // 涓烘帴鍙f坊鍔犻攣鍥炬爣
});
  • 鎺ヤ笅鏉ュ湪 ThreeController 涓柊澧炰竴涓帴鍙f潵鍋氶獙璇?
/// <summary>
/// ThreeAuthorize
/// </summary>
/// <returns></returns>
[HttpGet, Authorize]
public string ThreeAuthorize()=> "Hello Authorize";
  • 閲嶆柊鍚姩绋嬪簭,鍗冲彲鍙戠幇娣诲姞浜?Authorize 鐗规€х殑鎺ュ彛宸茬粡鍔犱笂浜嗛攣.

闅愯棌鎺ュ彛

  • 鏈変簺鍦烘櫙涓?鎴戜滑甯屾湜鏌愪簺鎺ュ彛鏄唴閮ㄤ娇鐢?涓嶅澶栧叕寮€.鐢氳嚦涓嶉渶瑕佽鍓嶇鐭ラ亾.杩欎釜鏃跺€欐垜浠氨鍙互鍦?Swagger 閲岄殣钘忚繖绉嶆帴鍙f垨鑰呮帶鍒跺櫒.杩欐牱鍋氱殑鐩殑鏄负浜嗛檷浣庡墠绔伐绋嬪笀浜х敓鐨勮瑙?鍚屾椂涔熷彲浠ュ皢杩囨椂鐨勬帴鍙i殣钘忚捣鏉?閬垮厤鍓嶇浣跨敤閿欒,铏界劧杩囨椂鎺ュ彛鍙互浣跨敤 Obsolete 鐗规€ф潵鏍囪,浣嗘槸浠栬繕鏄兘鍦?Swagger 涓婄湅瑙?
  • 涓轰簡闅愯棌鎺ュ彛,鎴戜滑闇€瑕佹柊寤轰竴涓壒鎬х敤鏉ユ爣璁伴渶瑕侀殣钘忕殑鎺ュ彛鎴栬€呮帶鍒跺櫒.
  • 鍦?Attributes 鏂囦欢澶逛腑娣诲姞 HiddenApiAttribute.cs 骞舵坊鍔犲涓嬩唬鐮?
/// <summary>
/// 琚鐗规€ф爣璁扮殑Action鎴栬€呮帶鍒跺櫒鍙湪Swagger鏂囨。涓殣钘?
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public sealed class HiddenApiAttribute : Attribute { }
  • 鍚屾椂杩橀渶瑕佸湪 SwaggerFilters 鏂囦欢澶逛腑娣诲姞 SwaggerHiddenApiFilter.cs 鏉ュ疄鐜拌鏍囪鎺ュ彛闅愯棌.
  • 鍏跺師鐞嗗氨鏄皢琚?HiddenApiAttribute 鏍囪鐨勬帴鍙d粠 SwaggerDoc 涓Щ闄ゆ潵杈惧埌涓嶆樉绀虹殑鐩殑.
/// <summary>
/// 鍦⊿wagger鏂囨。涓殣钘忔帴鍙?/span>
/// </summary>
// ReSharper disable once UnusedMember.Global
// ReSharper disable once ClassNeverInstantiated.Global
public sealed class SwaggerHiddenApiFilter : IDocumentFilter
{
/// <summary>
/// Apply
/// </summary>
/// <param name="swaggerDoc"></param>
/// <param name="context"></param>
public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
{
foreach (var apiDescription in context.ApiDescriptions)
{
#pragma warning disable IDE0048
if (!apiDescription.TryGetMethodInfo(out var method) || !method.ReflectedType!.IsDefined(typeof(HiddenApiAttribute)) && !method.IsDefined(typeof(HiddenApiAttribute)))
#pragma warning restore IDE0048
continue;
var key=$"/{apiDescription.RelativePath}";
if (key.Contains('?'))
{
var index=key.IndexOf("?", StringComparison.Ordinal);
key=key[..index];
}
_=swaggerDoc.Paths.Remove(key);
}
}
}
  • 璇ヨ繃婊ゅ櫒鐨勪娇鐢ㄦ柟娉曞拰鍓嶈竟鐨?SwaggerAuthorizeFilter 涓€鏍?鍙渶瑕佷竴琛屼唬鐮?
builder.Services.AddSwaggerGen(c=>
{
...
c.OperationFilter<SwaggerAuthorizeFilter>(); // 涓烘帴鍙f坊鍔犻攣鍥炬爣
c.DocumentFilter<SwaggerHiddenApiFilter>(); // 娣诲姞闅愯棌鎺ュ彛杩囨护
});
  • 鎴戜滑鍐嶅湪 ThreeController 涓垱寤轰竴涓帴鍙f潵楠岃瘉璇ョ壒鎬ф槸鍚︾敓鏁?
/// <summary>
/// ThreeHidden
/// </summary>
/// <returns></returns>
[HttpGet, HiddenApi]
public string ThreeHidden()=> "Hello Hidden";
  • 閲嶆柊鍚姩绋嬪簭鍚?鎴戜滑浼氬彂鐜?ThreeHidden 骞舵湭鏄剧ず鍦?Swagger 涓鏄庢垜浠垚鍔熶簡.杩欓噷灏变笉鍐嶆埅鍥句簡.鍙互涓嬭浇婧愮爜鏌ョ湅鏁堟灉.
  • 鍚屾牱璇ョ壒鎬у彲浠ヤ綔鐢ㄤ簬鎺у埗鍣?杩欐牱鏁翠釜鎺у埗鍣ㄤ腑鐨勬帴鍙e潎涓嶄細鏄剧ず.

涓哄弬鏁版坊鍔犻粯璁ゅ€兼樉绀?/span>

  • 鐩墠鎰熻杩欎釜鍔熻兘 Swagger 鏀寔杩樹笉澶熷畬缇?鏈変竴浜涚被鍨嬬殑鏁版嵁鏃犳硶姝e父閰嶇疆,涓嶈繃鍚庢湡浼氳秺鏉ヨ秺瀹屽杽鐨?
  • 杩欓噷鎴戜滑涔熸槸鍒╃敤涓€涓?NET 妗嗘灦鑷甫鐨勭壒鎬?DefaultValue 鏉ュ疄鐜?涓嶈繃鍚屾牱闇€瑕佽嚜宸卞啓涓€涓?Filter 鎵嶈兘瀹炵幇杩欑鍔熻兘.
  • 棣栧厛鎴戜滑鍦?SwaggerFilters 鏂囦欢澶逛腑鏂板缓涓€涓?Filter,鍚嶅瓧鍙?SwaggerSchemaFilter.cs 骞舵坊鍔犲涓嬩唬鐮?
/// <summary>
/// 娣诲姞榛樿鍊兼樉绀?/span>
/// </summary>
// ReSharper disable once UnusedMember.Global
// ReSharper disable once ClassNeverInstantiated.Global
public sealed class SwaggerSchemaFilter : ISchemaFilter
{
/// <summary>
/// Apply
/// </summary>
/// <param name="schema"></param>
/// <param name="context"></param>
public void Apply(OpenApiSchema schema, SchemaFilterContext context)
{
if (schema.Properties is ) return;
foreach (var info in context.Type.GetProperties())
{
// Look for class attributes that have been decorated with "[DefaultAttribute(...)]".
var defaultAttribute=info.GetCustomAttribute<DefaultValueAttribute>();
if (defaultAttribute is ) continue;
foreach (var property in schema.Properties)
{
// Only assign default value to the proper element.
if (ToCamelCase(info.Name) !=property.Key) continue;
property.Value.Example=defaultAttribute.Value as IOpenApiAny;
break;
}
}
}

/// <summary>
/// 杞垚椹煎嘲褰㈠紡,杩欓噷闇€瑕佹敞鎰忎竴涓?鍙兘闇€瑕佹寜鐓т綘鑷繁鐨勫瓧娈佃鑼冭繘琛岃嚜瀹氫箟杞崲,涓嶇劧瀵逛笉涓?
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
private static string ToCamelCase(string name)=> char.ToLowerInvariant(name[0]) + name[1..];
}
  • 鍏朵腑 ToCamelCase 鏂规硶闇€瑕佹敞鎰忎竴涓?鎴戜滑浣跨敤榛樿鐨勯┘宄板舰寮忔潵琛ㄧず JSON 瀛楁,鎵€浠ヨ繖閲岃嫢鏄笉涓€鏍?闇€瑕佽嚜宸卞鐞嗕竴涓?
  • 鎺ヤ笅鏉ュ湪 Program.cs 涓厤缃?SwaggerSchemaFilter.
builder.Services.AddSwaggerGen(c=>
{
...
c.DocumentFilter<SwaggerHiddenApiFilter>(); // 娣诲姞闅愯棌鎺ュ彛杩囨护
c.SchemaFilter<SwaggerSchemaFilter>(); // 娣诲姞榛樿鍊兼樉绀?/span>
});
  • 杩欎竴鍒囬兘鍋氬ソ浜嗗悗,鐜板湪鍥炲埌 FirstController.cs 涓?灏?PostParameter 绫昏皟鏁翠笅,涓轰簡鐩磋鐐?鎴戝姞浜嗕竴涓柊鐨勫璞?骞惰皟鏁存垚濡備笅浠g爜:
/// <summary>
/// POST鍙傛暟妯℃嫙
/// </summary>
public class PostParameter : PutParameter
{
/// <summary>
/// Name
/// </summary>
[DefaultValue("寮犱笁")]
public string Name { get; set; }=string.Empty;

/// <summary>
/// Age
/// </summary>
[DefaultValue(20)]
public int Age { get; set; }

/// <summary>
/// 鐢熸棩
/// </summary>
[DefaultValue(typeof(DateTime), "2023-04-01")]
public DateTime Birthday { get; set; }=DateTime.Now;
}
  • 鍦ㄤ笂杩颁緥瀛愪腑,鎴戠粰 Name 瀛楁娣诲姞浜嗛粯璁ゅ€?寮犱笁,Age 娣诲姞浜嗛粯璁ゅ€?20,鏂板 Birthday 瀛楁骞惰缃粯璁ゅ€间负 23 骞存剼浜鸿妭.
  • DefaultValue 鐗规€х涓€涓弬鏁颁负鏁版嵁绫诲瀷,鎻愪緵浜嗗嚑涓粯璁ょ殑閲嶈浇,鑻ユ槸娌℃湁鐨勮瘽,鍙互浣跨敤 typeof 鏉ユ寚瀹氱被鍨?骞剁敤瀛楃涓茬殑褰㈠紡璁剧疆榛樿鍊兼樉绀?
  • 鍋氬ソ杩欎竴鍒囧悗,鍚姩绋嬪簭,鏉ヨ瀵熼粯璁ゅ€兼槸鍚﹁缃垚鍔?

  • 鍙互鐪嬪埌杩欎竴鍒囧潎鎸夌収鎴戜滑鐨勯鏈熷疄鐜?

  • 鍒拌繖閲屾垜鍦ㄥ伐浣滀腑浣跨敤鐨勫姛鑳藉凡缁忎粙缁嶅畬,鑻ユ槸浣犳湁鍏朵粬鐨勭帺娉?璇锋彁渚?PR馃榿 鎴栬€呭憡璇夋垜涓€璧风爺绌?

  • 婧愮爜宸蹭笂浼犺嚦 GitHub: https://github.com/joesdu/Swagger.Sample

  • 浠ヤ笂鍔熻兘鍚屾牱鍦ㄦ垜鐨勫簱涓凡缁忛瀹氫箟.鍙互鍙傝€僂asilyNET.WebCore

  • Nuget 鍦板潃: https://www.nuget.org/packages/EasilyNET.WebCore

  • GitHub 鍦板潃: https://github.com/EasilyNET/EasilyNET

  • 鏈枃閾炬帴: https://github.com/EasilyNET/docs

HP7宸茬粡鍙戝竷浜? 浣滀负PHP10骞存潵鏈€澶х殑鐗堟湰鍗囩骇, 鏈€澶х殑鎬ц兘鍗囩骇, PHP7鍦ㄥ鏀剧殑娴嬭瘯涓兘琛ㄧ幇鍑哄緢鏄庢樉鐨勬€ц兘鎻愬崌, 鐒惰€? 涓轰簡璁╁畠鑳藉彂鎸ュ嚭鏈€澶х殑鎬ц兘, 鎴戣繕鏄湁鍑犱欢浜嬫兂鎻愰啋涓?

PHP7 VS PHP5.6

1. Opcache

璁板緱鍚敤Zend Opcache, 鍥犱负PHP7鍗充娇涓嶅惎鐢∣pcache閫熷害涔熸瘮PHP-5.6鍚敤浜哋pcache蹇? 鎵€浠ヤ箣鍓嶆祴璇曟椂鏈熷氨鍙戠敓浜嗘湁浜轰竴鐩存病鏈夊惎鐢∣pcache鐨勪簨鎯? 鍚敤Opcache闈炲父绠€鍗? 鍦╬hp.ini閰嶇疆鏂囦欢涓姞鍏?

zend_extension=opcache.so
opcache.enable=1
opcache.enable_cli=1"

2. 浣跨敤鏂扮殑缂栬瘧鍣?/strong>

浣跨敤鏂颁竴鐐圭殑缂栬瘧鍣? 鎺ㄨ崘GCC 4.8浠ヤ笂, 鍥犱负鍙湁GCC 4.8浠ヤ笂PHP鎵嶄細寮€鍚疓lobal Register for opline and execute_data鏀寔, 杩欎釜浼氬甫鏉?%宸﹀彸鐨勬€ц兘鎻愬崌(Wordpres鐨凲PS瑙掑害琛¢噺)

鍏跺疄GCC 4.8浠ュ墠鐨勭増鏈篃鏀寔, 浣嗘槸鎴戜滑鍙戠幇瀹冩敮鎸佺殑鏈塀ug, 鎵€浠ュ繀椤绘槸4.8浠ヤ笂鐨勭増鏈墠浼氬紑鍚繖涓壒鎬?

3. HugePage

鎴戜箣鍓嶇殑鏂囩珷涔熶粙缁嶈繃: 璁╀綘鐨凱HP7鏇村揩涔婬ugepage , 棣栧厛鍦ㄧ郴缁熶腑寮€鍚疕ugePages, 鐒跺悗寮€鍚疧pcache鐨刪uge_code_pages.

浠ユ垜鐨凜entOS 6.5涓轰緥, 閫氳繃:

$sudo sysctl vm.nr_hugepages=512

鍒嗛厤512涓鐣欑殑澶ч〉鍐呭瓨:

$ cat /proc/meminfo | grep Huge
AnonHugePages: 106496 kB
HugePages_Total: 512
HugePages_Free: 504
HugePages_Rsvd: 27
HugePages_Surp: 0
Hugepagesize: 2048 kB

鐒跺悗鍦╬hp.ini涓姞鍏?

 opcache.huge_code_pages=1

杩欐牱涓€鏉? PHP浼氭妸鑷韩鐨則ext娈? 浠ュ強鍐呭瓨鍒嗛厤涓殑huge閮介噰鐢ㄥぇ鍐呭瓨椤垫潵淇濆瓨, 鍑忓皯TLB miss, 浠庤€屾彁楂樻€ц兘.

4. Opcache file cache

寮€鍚疧pcache File Cache(瀹為獙鎬?, 閫氳繃寮€鍚繖涓? 鎴戜滑鍙互璁㎡pcache鎶妎pcode缂撳瓨缂撳瓨鍒板閮ㄦ枃浠朵腑, 瀵逛簬涓€浜涜剼鏈? 浼氭湁寰堟槑鏄剧殑鎬ц兘鎻愬崌.

鍦╬hp.ini涓姞鍏?

opcache.file_cache=/tmp

杩欐牱PHP灏变細鍦?tmp鐩綍涓婥ache涓€浜汷pcode鐨勪簩杩涘埗瀵煎嚭鏂囦欢, 鍙互璺≒HP鐢熷懡鍛ㄦ湡瀛樺湪.

5. PGO

鎴戜箣鍓嶇殑鏂囩珷: 璁╀綘鐨凱HP7鏇村揩(GCC PGO) 涔熶粙缁嶈繃, 濡傛灉浣犵殑PHP鏄笓闂ㄤ负涓€涓」鐩湇鍔? 姣斿鍙槸涓轰綘鐨刉ordpress, 鎴栬€卍rupal, 鎴栬€呭叾浠栦粈涔? 閭d箞浣犲氨鍙互灏濊瘯閫氳繃PGO, 鏉ユ彁鍗嘝HP, 涓撻棬涓轰綘鐨勮繖涓」鐩彁楂樻€ц兘.

鍏蜂綋鐨? 浠ordpress 4.1涓轰紭鍖栧満鏅?. 棣栧厛鍦ㄧ紪璇慞HP鐨勬椂鍊欓鍏?

$ make prof-gen

鐒跺悗鐢ㄤ綘鐨勯」鐩缁働HP, 姣斿瀵逛簬Wordpress:

$ sapi/cgi/php-cgi -T 100 /home/huixinchen/local/www/htdocs/wordpress/index.php >/dev/null

涔熷氨鏄php-cgi璺?00閬峸ordpress鐨勯椤? 浠庤€岀敓鎴愪竴浜涘湪杩欎釜杩囩▼涓殑profile淇℃伅.

鏈€鍚?

$ make prof-clean
$ make prof-use && make install

杩欎釜鏃跺€欎綘缂栬瘧寰楀埌鐨凱HP7灏辨槸涓轰綘鐨勯」鐩噺韬墦閫犵殑鏈€楂樻€ц兘鐨勭紪璇戠増鏈?