
C#で記述された、RESTFUL HTTP/HTTPSリクエストを処理するためのシンプルでスケーラブル、高速、非同期Webサーバー。
| パッケージ | nugetバージョン | ダウンロード |
|---|---|---|
| ワトソン | ||
| watson.lite | ||
| watson.core |
NugetでWatson.Coreパッケージ名を使用できるようにしてくれた@damiendennehyに感謝します!
このプロジェクトは、.NETランタイムなどの他のプロジェクトとともに、.NET Foundationの一部です。
SendChunk isFinal Booleanプロパティとして受け入れるようになりましたTest.ServerSentEventsプロジェクトが含まれていますワトソン・ウェブサーバーをより良くするのを助けてくれた人たちに特別な感謝を拡大したいと思います。
ワトソンは、オペレーティングシステム内の基礎となるhttp.sysの上で動作するウェブサーバーです。 watson.liteは、Httpserverliteの統合によって作成されました。 watson.liteはhttp.sysに依存せず、cavemantcpが提供するTCP実装を使用して実装されています。
http.sys (またはその欠如)への依存性は、2つのライブラリ間に微妙な違いを生み出しますが、それぞれの構成と管理は一貫している必要があります。
HTTP実装はユーザースペースにあるため、Watson.Liteは一般にWatsonよりもパフォーマンスが低くなります。
127.0.0.1またはlocalhost以外のIPをバインドする場合、標高(管理特権)が必要になる場合がありますX509Certificate2提供する必要がありますWatsonとWatson.Liteは常に次の順序でルーティングします( Webserver.Routesを使用して構成):
.Preflightプリフライトリクエストの処理(通常、HTTPメソッドOPTIONSを使用).PreRoutingルーティングの決定が行われる前に常に呼び出されます.PreAuthentication次のルーティンググループ。.Static静的ルート、例:HTTPメソッドと明示的なURL.Contentファイルのサービングルート、たとえばファイルを読み取ることができるディレクトリなど.Parameterパスで変数が指定されているルート、EG /user/{id}.Dynamic正規表現によってURLが定義されるルート.AuthenticateRequest認証されていないルートと認証されたルートの間の境界ルート.PostAuthentication -.PREAUTHENTICATION .PreAuthentication同一の構造を持つルーティンググループ.Defaultデフォルトルート。すべてのリクエストは、以前にルーティングされていない場合はここにあります.PostRouting通常はロギングとテレメトリのために、常に呼び出されます認証を使用したくない場合は、 .PreAuthenticationルーティンググループにルートをマッピングする必要があります(ただし、技術的には、 AuthenticateRequestメソッドがnullであると仮定して.PostAuthenticationまたは.Defaultに配置できます。
一般的なルールとして、 .PostRoutingルートにいる間、データをHttpResponseに送信しようとしないでください。応答が既に送信されている場合、 .PostRoutingの内部の試みは失敗します。
.AuthenticateRequestで認証を実装することをお勧めします。リクエストが認証に失敗する場合は、そのルート内の応答を返します。 HttpContextBaseクラスには、認証関連またはセッション関連のメタデータ、特に.Metadataを保持できるプロパティがあります。
デフォルトでは、WatsonとWatson.Liteは、すべてのインバウンド接続を許可します。
Server.AccessControl.DenyList.Add(ip, netmask)を使用します。Server.AccessControl.Mode = AccessControlMode.DefaultDenyServer.AccessControl.PermitList.Add(ip, netmask)完全な例については、 Test.Defaultを参照してください。
using System . IO ;
using System . Text ;
using WatsonWebserver ;
static void Main ( string [ ] args )
{
WebserverSettings settings = new WebserverSettings ( "127.0.0.1" , 9000 ) ;
Webserver server = new Webserver ( settings , DefaultRoute ) ;
server . Start ( ) ;
Console . ReadLine ( ) ;
}
static async Task DefaultRoute ( HttpContextBase ctx ) =>
await ctx . Response . Send ( "Hello from the default route!" ) ;次に、ブラウザをhttp://127.0.0.1:9000/に開きます。
完全な例については、 Test.Routingを参照してください。
using System . IO ;
using System . Text ;
using System . Text . RegularExpressions ;
using WatsonWebserver ;
static void Main ( string [ ] args )
{
WebserverSettings settings = new WebserverSettings ( "127.0.0.1" , 9000 ) ;
Webserver server = new Webserver ( settings , DefaultRoute ) ;
// add content routes
server . Routes . PreAuthentication . Content . Add ( "/html/" , true ) ;
server . Routes . PreAuthentication . Content . Add ( "/img/watson.jpg" , false ) ;
// add static routes
server . Routes . PreAuthentication . Static . Add ( HttpMethod . GET , "/hello/" , GetHelloRoute ) ;
server . Routes . PreAuthentication . Static . Add ( HttpMethod . GET , "/howdy/" , async ( HttpContextBase ctx ) =>
{
await ctx . Response . Send ( "Hello from the GET /howdy static route!" ) ;
return ;
} ) ;
// add parameter routes
server . Routes . PreAuthentication . Parameter . Add ( HttpMethod . GET , "/{version}/bar" , GetBarRoute ) ;
// add dynamic routes
server . Routes . PreAuthentication . Dynamic . Add ( HttpMethod . GET , new Regex ( "^/foo/ \ d+$" ) , GetFooWithId ) ;
server . Routes . PreAuthentication . Dynamic . Add ( HttpMethod . GET , new Regex ( "^/foo/?$" ) , GetFoo ) ;
// start the server
server . Start ( ) ;
Console . WriteLine ( "Press ENTER to exit" ) ;
Console . ReadLine ( ) ;
}
static async Task GetHelloRoute ( HttpContextBase ctx ) =>
await ctx . Response . Send ( "Hello from the GET /hello static route!" ) ;
static async Task GetBarRoute ( HttpContextBase ctx ) =>
await ctx . Response . Send ( "Hello from the GET /" + ctx . Request . Url . Parameters [ "version" ] + "/bar route!" ) ;
static async Task GetFooWithId ( HttpContextBase ctx ) =>
await ctx . Response . Send ( "Hello from the GET /foo/[id] dynamic route!" ) ;
static async Task GetFoo ( HttpContextBase ctx ) =>
await ctx . Response . Send ( "Hello from the GET /foo/ dynamic route!" ) ;
static async Task DefaultRoute ( HttpContextBase ctx ) =>
await ctx . Response . Send ( "Hello from the default route!" ) ; server . Routes . PreAuthentication . Static . Add ( HttpMethod . GET , "/hello/" , GetHelloRoute , MyExceptionRoute ) ;
static async Task GetHelloRoute ( HttpContextBase ctx ) => throw new Exception ( "Whoops!" ) ;
static async Task MyExceptionRoute ( HttpContextBase ctx , Exception e )
{
ctx . Response . StatusCode = 500 ;
await ctx . Response . Send ( e . Message ) ;
} Webserver server = new Webserver ( "127.0.0.1" , 9000 , false , DefaultRoute ) ;
// set default permit (permit any) with deny list to block specific IP addresses or networks
server . Settings . AccessControl . Mode = AccessControlMode . DefaultPermit ;
server . Settings . AccessControl . DenyList . Add ( "127.0.0.1" , "255.255.255.255" ) ;
// set default deny (deny all) with permit list to permit specific IP addresses or networks
server . Settings . AccessControl . Mode = AccessControlMode . DefaultDeny ;
server . Settings . AccessControl . PermitList . Add ( "127.0.0.1" , "255.255.255.255" ) ; ワトソンは、チャンクデータの受信とチャンクデータの送信の両方をサポートしています(ヘッダーTransfer-Encoding: chunked付き)。
サンプルの実装については、 Test.ChunkServerを参照してください。
static async Task UploadData ( HttpContextBase ctx )
{
if ( ctx . Request . ChunkedTransfer )
{
bool finalChunk = false ;
while ( ! finalChunk )
{
Chunk chunk = await ctx . Request . ReadChunk ( ) ;
// work with chunk.Length and chunk.Data (byte[])
finalChunk = chunk . IsFinalChunk ;
}
}
else
{
// read from ctx.Request.Data stream
}
} static async Task DownloadChunkedFile ( HttpContextBase ctx )
{
using ( FileStream fs = new FileStream ( "./img/watson.jpg" , , FileMode . Open , FileAccess . Read ) )
{
ctx . Response . StatusCode = 200 ;
ctx . Response . ChunkedTransfer = true ;
byte [ ] buffer = new byte [ 4096 ] ;
while ( true )
{
int bytesRead = await fs . ReadAsync ( buffer , 0 , buffer . Length ) ;
byte [ ] data = new byte [ bytesRead ] ;
Buffer . BlockCopy ( buffer , 0 , bytesRead , data , 0 ) ; // only copy the read data
if ( bytesRead > 0 )
{
await ctx . Response . SendChunk ( data , false ) ;
}
else
{
await ctx . Response . SendChunk ( Array . Empty < byte > ( ) , true ) ;
break ;
}
}
}
return ;
} ワトソンは、サーバーセントイベントの送信をサポートしています。サンプルの実装については、 Test.ServerSentEventsを参照してください。 SendEventメソッドnn data:の準備を処理します。
static async Task SendEvents ( HttpContextBase ctx )
{
ctx . Response . StatusCode = 200 ;
ctx . Response . ServerSentEvents = true ;
while ( true )
{
string data = GetNextEvent ( ) ; // your implementation
if ( ! String . IsNullOrEmpty ( data ) )
{
await ctx . Response . SendEvent ( data ) ;
}
else
{
break ;
}
}
return ;
} HostBuilder 、サーバークラスを直接使用する代わりに、一連の設定とルートを導入することにより、サーバーをより簡単にセットアップするのに役立ちます。この素晴らしい機能を作成してくれた @sapurtcomputer30に感謝します!
完全なサンプル実装については、 Test.HostBuilderを参照してください。
using WatsonWebserver . Extensions . HostBuilderExtension ;
Webserver server = new HostBuilder ( "127.0.0.1" , 8000 , false , DefaultRoute )
. MapStaticRoute ( HttpMethod . GET , GetUrlsRoute , "/links" )
. MapStaticRoute ( HttpMethod . POST , CheckLoginRoute , "/login" )
. MapStaticRoute ( HttpMethod . POST , TestRoute , "/test" )
. Build ( ) ;
server . Start ( ) ;
Console . WriteLine ( "Server started" ) ;
Console . ReadKey ( ) ;
static async Task DefaultRoute ( HttpContextBase ctx ) =>
await ctx . Response . Send ( "Hello from default route!" ) ;
static async Task GetUrlsRoute ( HttpContextBase ctx ) =>
await ctx . Response . Send ( "Here are your links!" ) ;
static async Task CheckLoginRoute ( HttpContextBase ctx ) =>
await ctx . Response . Send ( "Checking your login!" ) ;
static async Task TestRoute ( HttpContextBase ctx ) =>
await ctx . Response . Send ( "Hello from the test route!" ) ; Watsonを127.0.0.1またはlocalhostでリッスンするように構成すると、ローカルマシン内から受け取ったリクエストにのみ応答します。
localhost以外の他のノードからのアクセスを構成するには、次を使用してください。
*または+使用します。管理者として実行する必要があります(オペレーティングシステムの制限)netshコマンドを使用して、オペレーティングシステム内でURL ACL、つまりURLバインディングを追加する必要がある場合があります。netsh http show urlaclを使用して既存のバインディングを確認してくださいnetsh http add urlacl url=http://[hostname]:[port]/ user=everyone listen=yeshostnameとport 、コンストラクターで使用している値です Watson.liteを127.0.0.1にリッスンするように構成すると、ローカルマシン内から受信したリクエストのみに応答します。
ローカルマシン以外の他のノードからのアクセスを構成するには、以下を使用してください。
*または+使用してください。管理者として実行する必要があります(オペレーティングシステムの制限)X509Certificate2オブジェクトTest.DockerプロジェクトとDocker.mdファイルを参照してください。
バージョン履歴については、changelog.mdを参照してください。