我正在编写面向公众的交易处理器。自然,我们在https://上运行,并且有效负载包含所有相关细节,因此我们将仅处理合法交易。但是,作为公共接口,任何其他邪恶的行为者毫无疑问都将在我的服务器上蒙上阴影,除非是因为烦人而已。
当我检测到这样的请求时,是否有可以终止的处理-不会在事务上浪费时间-却不会将响应发送给客户端?基本上,我想迫使邪恶的客户端进入超时状态,以至于减少其他烦恼我服务器的能力。
代码如下:
public class Webhook : IHttpModule
{
/// <summary>
/// You will need to configure this module in the Web.config file of your
/// web and register it with IIS before being able to use it. For more information
/// see the following link: http://go.microsoft.com/?linkid=8101007
/// </summary>
private bool m_sslRequired = false;
#region IHttpModule Members
<snip...>
#endregion
private void OnBeginRequest(object sender, EventArgs e)
{
WriteTrace("Begin OnBeginRequest");
HttpContext ctx = HttpContext.Current;
try
{
string processor = ctx.Request.Params["p"];
if (processor != null && processor != "")
{
PluginProcessor(processor, ctx);
}
}
catch (Exception ex)
{
ctx.Response.StatusCode = 500;
ctx.Response.Write("ERROR");
}
ctx.ApplicationInstance.CompleteRequest();
WriteTrace("End OnBeginRequest");
}
private void PluginProcessor(string processor, HttpContext ctx)
{
string pluginSpec = AppConfig.GetAppSetting(processor.Trim().ToLower());
if (pluginSpec != "")
{
IWebhookProcessor proc = CreateProcessor(pluginSpec, ctx);
proc.Process(ctx);
}
}
private IWebhookProcessor CreateProcessor(string Processor, HttpContext ctx)
{
string assembly;
string typeName;
typeName = Processor.Substring(0, Processor.IndexOf(",")).Trim();
assembly = Path.Combine(ctx.Request.PhysicalApplicationPath, "bin", Processor.Substring(Processor.IndexOf(",") + 1).Trim());
var obj = Activator.CreateInstanceFrom(assembly, typeName);
return (Interfaces.IWebhookProcessor)obj.Unwrap();
}
}
因此,如果请求未映射到事务处理程序,则我想“挂起”客户端,但不希望这种方式占用服务器资源。
感谢您的建议!
答案 0 :(得分:0)
我认为您可以做的最好的事情是使用HttpRequest.Abort()
,它不会使客户端挂起,但是会立即切断TCP连接。甚至文档都说它适用于这种情况:
您可以使用此方法来响应恶意HTTP客户端的攻击。</ p>
您将像这样使用它:
ctx.Request.Abort();
在浏览器中,您会看到“连接重置”错误。
另一种选择是发回意外的HTTP状态(例如400)或我个人的收藏夹418。
更新:如果您真的想让客户端等待,则可以实现自己的HttpModule
,以便可以进行异步{{1} }事件,然后使用BeginRequest
。
Task.Delay()
类看起来像这样:
HttpModule
然后将模块添加到您的web.config中(将名称空间替换为应用程序的名称空间):
public class AsyncHttpModule : IHttpModule {
public void Dispose() { }
public void Init(HttpApplication app) {
var wrapper = new EventHandlerTaskAsyncHelper(DoAsyncWork);
app.AddOnBeginRequestAsync(wrapper.BeginEventHandler, wrapper.EndEventHandler);
}
private async Task DoAsyncWork(object sender, EventArgs e) {
var app = (HttpApplication) sender;
var ctx = app.Context;
if (shouldDie) { //whatever your criteria is
await Task.Delay(60000); //wait for one minute
ctx.Request.Abort(); //kill the connection without replying
}
}
}
由于这是异步的,因此它在等待时不会占用线程。传入的其他请求将使用同一线程(我对此进行了测试)。
但是,由于请求仍在进行中,因此它仍将请求上下文保留在内存中。因此,如果他们用1000多个请求打了你,那么所有1000多个请求都会在内存中保留60秒钟。而如果您只是立即使用<system.webServer>
<modules>
<add name="AsyncHttpModule" type="MyNamespace.AsyncHttpModule" />
</modules>
</system.webServer>
,则会立即将其从内存中删除。