この例に従って、同期 HTTP サーバー (.NET の HttpListener を使用) を非同期に変換しました。それは機能しますが、Google Chrome から発行するすべてのリクエストに対して、アドレス バーで Enter キーを押すか、F5 を押すと、2 つのリクエストが返されます。最初のものは完全に処理され、応答はブラウザーで適切にレンダリングされます。
ただし、表示されるべきではない 2 番目の要求には、空のクエリ文字列があります (私のサーバーはコンソール アプリケーションであるため、Console.WriteLine
.
サーバーが同期のときはこのようなことは起こらなかったので、非同期モデルに移行するときに何かを台無しにしたに違いありません。
コードは次のとおりです。
using System;
using System.Diagnostics;
using System.Net;
namespace MyWebServer{
internal static class MyHTTPServer {
private static int mPortNumber = 7091;
private static HttpListener mListener;
private static MyCustomHttpHandler mHttpHandler;
//Omitted some auxiliary methods to print stuff to Console,
//like WriteError and WriteRequestHeaderInformation
public static void Main( String[] pArg ) {
AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionTrapper;
HttpHandler = new MyCustomHttpHandler();
mPortNumber = Convert.ToInt32( pArg[0] );
Console.WriteLine( "Starting the HttpListener on port:{0}", mPortNumber );
InitialiseListener();
Console.WriteLine( "Listener started on port: {0}, waiting for requests.", mPortNumber );
Console.WriteLine( "Listening. Press Enter to stop." );
Console.ReadLine();
if( mListener.IsListening )
mListener.Stop();
}
private static void InitialiseListener() {
try {
mListener = new HttpListener {
AuthenticationSchemes = AuthenticationSchemes.Basic
};
string prefix = string.Format( "http://+:{0}/", mPortNumber );
mListener.Prefixes.Add( prefix );
mListener.AuthenticationSchemes = AuthenticationSchemes.Anonymous;
mListener.Start();
mListener.BeginGetContext( RequestReceived, null );
} catch( Exception ex ) {
WriteError( ex.Message );
}
}
private static void RequestReceived( IAsyncResult result ) {
var timer = new Stopwatch();
Console.WriteLine( "---Request Received----" );
timer.Reset();
timer.Start();
//Retrieve context; on error, print message and wait for another request
HttpListenerContext context = null;
try {
context = mListener.EndGetContext( result );
} catch( HttpListenerException e ) {
WriteError( e.ToString() );
if( mListener.IsListening )
mListener.BeginGetContext( RequestReceived, null );
return;
}
//Process request and send response
mListener.BeginGetContext( RequestReceived, null );
try {
WriteRequestHeaderInformation( context );
CreateResponseDocument( context );
} catch( Exception ex ) {
WriteError( ex.Message );
}
Console.WriteLine( "----Request processed in {0} milliseconds ----", timer.ElapsedMilliseconds );
}
private static void CreateResponseDocument( HttpListenerContext pHttpListenerContext ) {
try {
byte[] htmlOutput = HttpHandler.ProcessRequest( pHttpListenerContext.Request.Url.LocalPath.Replace( "/", "" ), pHttpListenerContext.Request.Url.Query.Replace( "?", "" ) );
if( htmlOutput != null && pHttpListenerContext.Response.OutputStream.CanWrite ) {
pHttpListenerContext.Response.Headers.Add( "Access-Control-Allow-Origin", "*" );
//pHttpListenerContext.Response.ContentType = "image/jpg";
pHttpListenerContext.Response.ContentType = "text/plain";
pHttpListenerContext.Response.OutputStream.Write( htmlOutput, 0, htmlOutput.Length );
}
pHttpListenerContext.Response.Close();
} catch( Exception ex ) {
WriteError( ex.Message );
}
}
}
}