銆佺敓鍛藉懆鏈燂細
浜屻€佸叆鍙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>
鉂?/span>鍦ㄥ悗绔紑鍙戜腑,甯哥敤 Web API 妯″紡,瀵瑰鎻愪緵 RESTful API 璁╁墠绔皟鐢?鑰屽叾涓渶钁楀悕鐨勫氨鏄嬌鐢?Swagger(淇楃О:涓濊鍝?,Swagger 涓嶄絾鎻愪緵浜嗛潪甯哥洿瑙傜殑欏甸潰渚涘紑鍙戣€呮煡鐪?榪樿兘閰嶇疆娉ㄩ噴璇存槑,鍒嗙粍絳?榪樺彲浠ョ洿鎺ュ湪嫻忚鍣ㄤ笂嫻嬭瘯鎺ュ彛,鍙互璇存槸,鐜板湪涓嶇敤 Swagger 鐨勫悗绔紑鍙戣€呬笉鏄釜濂藉紑鍙戣€?鏈枃灝嗛拡瀵規垜鍦ㄦ棩甯稿伐浣滀腑浣跨敤 Swagger 鐨勪竴浜涙€葷粨鍜屼緥瀛?鍩烘湰涓婂睘浜庡鍒朵唬鐮佸氨鑳界敤.
鉂?/span>
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();
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>}
<PropertyGroup>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
</PropertyGroup>
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();
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);
}
}
}
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; }
}
// 鏂囨。鏍囬
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淇℃伅
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();
/// <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";
}
/// <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" });
}
}
builder.Services.AddSwaggerGen(c=>
{
...
c.DocInclusionPredicate((docName, apiDescription)=>
{
...
});
c.OperationFilter<SwaggerAuthorizeFilter>(); // 涓烘帴鍙f坊鍔犻攣鍥炬爣
});
/// <summary>
/// ThreeAuthorize
/// </summary>
/// <returns></returns>
[HttpGet, Authorize]
public string ThreeAuthorize()=> "Hello Authorize";
/// <summary>
/// 琚鐗規€ф爣璁扮殑Action鎴栬€呮帶鍒跺櫒鍙湪Swagger鏂囨。涓殣钘?
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public sealed class HiddenApiAttribute : Attribute { }
/// <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);
}
}
}
builder.Services.AddSwaggerGen(c=>
{
...
c.OperationFilter<SwaggerAuthorizeFilter>(); // 涓烘帴鍙f坊鍔犻攣鍥炬爣
c.DocumentFilter<SwaggerHiddenApiFilter>(); // 娣誨姞闅愯棌鎺ュ彛榪囨護
});
/// <summary>
/// ThreeHidden
/// </summary>
/// <returns></returns>
[HttpGet, HiddenApi]
public string ThreeHidden()=> "Hello Hidden";
/// <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..];
}
builder.Services.AddSwaggerGen(c=>
{
...
c.DocumentFilter<SwaggerHiddenApiFilter>(); // 娣誨姞闅愯棌鎺ュ彛榪囨護
c.SchemaFilter<SwaggerSchemaFilter>(); // 娣誨姞榛樿鍊兼樉紺?/span>
});
/// <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;
}
鍙互鐪嬪埌榪欎竴鍒囧潎鎸夌収鎴戜滑鐨勯鏈熷疄鐜?
鍒拌繖閲屾垜鍦ㄥ伐浣滀腑浣跨敤鐨勫姛鑳藉凡緇忎粙緇嶅畬,鑻ユ槸浣犳湁鍏朵粬鐨勭帺娉?璇鋒彁渚?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灝辨槸涓轟綘鐨勯」鐩噺韜墦閫犵殑鏈€楂樻€ц兘鐨勭紪璇戠増鏈?
*請認真填寫需求信息,我們會在24小時內與您取得聯系。