Commit 9c8dd029 by lcx

Merge branch 'feature/限流中间件' into develop

parents 259016d2 67e7db5b
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.Swagger;
using System;
using System.Collections.Generic;
......@@ -16,7 +17,7 @@ public static void AddSwaggerConfiguration(this IServiceCollection services)
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new Info { Version = "v1.0", Title = "绩效API接口" });
c.SwaggerDoc("v1", new OpenApiInfo { Version = "v1.0", Title = "绩效API接口" });
//var xmlPath = new string[]
//{
......@@ -34,13 +35,22 @@ public static void AddSwaggerConfiguration(this IServiceCollection services)
c.IncludeXmlComments(xmlPathsss, true);
// Token绑定到ConfigureServices
var security = new Dictionary<string, IEnumerable<string>> { { "Performance API", new string[] { } }, };
var security = new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference{ Type = ReferenceType.SecurityScheme, Id = "Bearer" }
},
new List<string>()
}
};
c.AddSecurityRequirement(security);
c.AddSecurityDefinition("Performance API", new ApiKeyScheme
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Description = "JWT授权(数据将在请求头中进行传输) 直接在下框中输入Bearer {token}(注意两者之间是一个空格)",
Name = "Authorization",
In = "HEADER"
In = ParameterLocation.Header
});
});
......
......@@ -41,58 +41,63 @@ public class RequestRateLimitingMiddleware
public async Task Invoke(HttpContext context)
{
if (options == null || options.Endpoints == null || !options.Endpoints.Any(t => context.Request.Path.ToString().StartsWith(t)))
await next(context);
var ip = httpContextAccessor.HttpContext.Connection.RemoteIpAddress.ToString();
var headers = context.Request.Headers;
if (headers.ContainsKey("X-Forwarded-For"))
if (!context.Response.HasStarted && options != null && options.Endpoints != null && options.Endpoints.Any(t => context.Request.Path.ToString().StartsWith(t)))
{
ip = IPAddress.Parse(headers["X-Forwarded-For"].ToString().Split(',', StringSplitOptions.RemoveEmptyEntries)[0]).ToString();
}
var ip = httpContextAccessor.HttpContext.Connection.RemoteIpAddress.ToString();
var requestKey = $"{ip}-{context.Request.Method}-{context.Request.Path}";
// logger.LogInformation($"请求地址:{requestKey}");
var cacheOptions = new MemoryCacheEntryOptions()
{
AbsoluteExpiration = DateTime.Now.AddSeconds(options.Period)
};
var headers = context.Request.Headers;
if (headers.ContainsKey("X-Forwarded-For"))
{
ip = IPAddress.Parse(headers["X-Forwarded-For"].ToString().Split(',', StringSplitOptions.RemoveEmptyEntries)[0]).ToString();
}
if (requestStore.TryGetValue(requestKey, out int hitCount))
{
if (hitCount < Limit)
var requestKey = $"{ip}-{context.Request.Method}-{context.Request.Path}";
// logger.LogInformation($"请求地址:{requestKey}");
var cacheOptions = new MemoryCacheEntryOptions()
{
await ProcessRequest(context, requestKey, hitCount, cacheOptions);
AbsoluteExpiration = DateTime.Now.AddSeconds(options.Period)
};
if (requestStore.TryGetValue(requestKey, out int hitCount))
{
if (hitCount < Limit)
{
await ProcessRequest(context, requestKey, hitCount, cacheOptions);
}
else
{
// X-RateLimit-RetryAfter:超出限制后能够再次正常访问的时间。
context.Response.Headers["X-RateLimit-RetryAfter"] = cacheOptions.AbsoluteExpiration?.ToString();
context.Response.StatusCode = StatusCodes.Status200OK;
context.Response.ContentType = "application/json; charset=utf-8";
var response = new ApiResponse
{
State = ResponseType.TooManyRequests,
Message = "访问过于频繁,请稍后重试"
};
await context.Response.WriteAsync(JsonHelper.Serialize(response));
}
}
else
{
// X-RateLimit-RetryAfter:超出限制后能够再次正常访问的时间。
//context.Response.Headers["X-RateLimit-RetryAfter"] = cacheOptions.AbsoluteExpiration?.ToString();
context.Response.StatusCode = StatusCodes.Status200OK;
context.Response.ContentType = "application/json; charset=utf-8";
var response = new ApiResponse
{
State = ResponseType.TooManyRequests,
Message = "访问过于频繁,请稍后重试"
};
await context.Response.WriteAsync(JsonHelper.Serialize(response));
await ProcessRequest(context, requestKey, hitCount, cacheOptions);
}
}
else
{
await ProcessRequest(context, requestKey, hitCount, cacheOptions);
await next(context);
}
}
private async Task ProcessRequest(HttpContext context, string requestKey, int hitCount, MemoryCacheEntryOptions cacheOptions)
{
hitCount++;
requestStore.Set(requestKey, hitCount, cacheOptions);
//// X-RateLimit-Limit:同一个时间段所允许的请求的最大数目
//context.Response.Headers["X-RateLimit-Limit"] = Limit.ToString();
//// X-RateLimit-Remaining:在当前时间段内剩余的请求的数量。
//context.Response.Headers["X-RateLimit-Remaining"] = (Limit - hitCount).ToString();
// X-RateLimit-Limit:同一个时间段所允许的请求的最大数目
context.Response.Headers["X-RateLimit-Limit"] = Limit.ToString();
// X-RateLimit-Remaining:在当前时间段内剩余的请求的数量。
context.Response.Headers["X-RateLimit-Remaining"] = (Limit - hitCount).ToString();
await next(context);
}
}
......
......@@ -55,7 +55,7 @@
<PackageReference Include="NLog" Version="4.5.11" />
<PackageReference Include="NLog.Extensions.Logging" Version="1.4.0" />
<PackageReference Include="NLog.Web.AspNetCore" Version="4.8.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="4.0.1" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.1.4" />
<PackageReference Include="Microsoft.AspNet.SignalR" Version="2.4.1" />
</ItemGroup>
......
......@@ -101,15 +101,15 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env)
app.UseStatusCodePagesWithReExecute("/error/{0}");
}
app.UseMiddleware<RequestRateLimitingMiddleware>();
app.UseCors("SignalrCore");
app.UseSignalR(routes => routes.MapHub<AllotLogHub>("/performance/allotLogHub"));
app.UseSwaggerSetup(Configuration);
app.UseMiddleware<RequestRateLimitingMiddleware>();
app.UseMvc();
app.UseSwaggerSetup(Configuration);
}
private void JsonOptions(MvcJsonOptions json)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment