
Serveur Web asynchrone simple, évolutif, rapide et asynchrone pour le traitement des demandes RESTful HTTP / HTTPS, écrite en C #.
| Emballer | Version Nuget | Téléchargements |
|---|---|---|
| Watson | ||
| Watson.lite | ||
| Watson.Core |
Un merci spécial à @Damiendennehy pour nous avoir permis d'utiliser le nom du package Watson.Core à Nuget!
Ce projet fait partie de la Fondation .NET ainsi que d'autres projets comme le .NET Runtime.
SendChunk accepte désormais isFinal comme une propriété BooleanTest.ServerSentEvents ProjetJe remercie spécialement ceux qui ont contribué à améliorer Watson Webserver.
Watson est un serveur Web qui fonctionne au-dessus du http.sys sous-jacent dans le système d'exploitation. Watson.lite a été créé en fusionnant HttpServerLite. Watson.Lite ne dépend pas de http.sys et est implémenté à l'aide d'une implémentation TCP fournie par CaveMantCP.
La dépendance à http.sys (ou son absence) crée des différences subtiles entre les deux bibliothèques, cependant, la configuration et la gestion de chacun doivent être cohérentes.
Watson.Lite est généralement moins performant que Watson, car l'implémentation HTTP est dans l'espace utilisateur.
127.0.0.1 ou localhostX509Certificate2 doit être fourni Watson et Watson.Lite roule toujours dans l'ordre suivant (configurer à l'aide de Webserver.Routes ):
.Preflight - Gestion des demandes de premier plan (généralement avec OPTIONS de méthode HTTP).PreRouting - toujours invoqué avant toute détermination du routage.PreAuthentication - Un groupe de routage, composé de:.Static - routes statiques, par exemple une méthode HTTP et une URL explicite.Content - Routes de service de fichiers, par exemple un répertoire où les fichiers peuvent être lus.Parameter - Routes où les variables sont spécifiées dans le chemin, par exemple /user/{id}.Dynamic - voies où l'URL est définie par une expression régulière.AuthenticateRequest - voie de démarcation entre les voies non authentifiées et authentifiées.PostAuthentication - Un groupe de routage avec une structure identique à .PreAuthentication Pré-authentification.Default - La route par défaut; Toutes les demandes vont ici si elles ne sont pas acheminées auparavant.PostRouting - toujours invoqué, généralement pour l'exploitation forestière et la télémétrie Si vous ne souhaitez pas utiliser l'authentification, vous devez cartographier vos itinéraires dans le groupe de routage .PreAuthentication (bien que techniquement, ils peuvent être placés dans .PostAuthentication ou .Default en supposant que la méthode AuthenticateRequest est nul.
En règle générale, n'essayez jamais d'envoyer des données à une HttpResponse dans la route .PostRouting . Si une réponse a déjà été envoyée, la tentative à l'intérieur de .PostRouting échouera.
Il est recommandé d'implémenter l'authentification dans .AuthenticateRequest . Si une demande échoue l'authentification, renvoyez une réponse dans cette voie. La classe HttpContextBase possède des propriétés qui peuvent contenir des métadonnées liées à l'authentification ou liées à la session, en particulier, .Metadata .
Par défaut, Watson et Watson.Lite permettra toutes les connexions entrantes.
Server.AccessControl.DenyList.Add(ip, netmask)Server.AccessControl.Mode = AccessControlMode.DefaultDenyServer.AccessControl.PermitList.Add(ip, netmask) Reportez-vous à Test.Default pour un exemple complet.
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!" ) ; Ensuite, ouvrez votre navigateur à http://127.0.0.1:9000/ .
Reportez-vous à Test.Routing pour un exemple complet.
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" ) ; Watson prend en charge les deux données de réception et l'envoi de données en morceaux (indiqué par le Transfer-Encoding: chunked ).
Reportez-vous à Test.ChunkServer pour un exemple de mise en œuvre.
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 ;
} Watson prend en charge l'envoi d'événements de serveur. Reportez-vous à Test.ServerSentEvents pour un exemple de mise en œuvre. La méthode SendEvent gère la mise en avant data: et la nn suivante à votre message.
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 vous aide à configurer votre serveur beaucoup plus facilement en introduisant une chaîne de paramètres et de routes au lieu d'utiliser directement la classe de serveur. Un merci spécial à @ sapurtcomputer30 pour avoir produit cette belle fonctionnalité!
Reportez-vous à Test.HostBuilder pour une implémentation complète de l'échantillon.
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!" ) ; Lorsque vous configurez Watson pour écouter sur 127.0.0.1 ou localhost , il ne répondra qu'aux demandes reçues de la machine locale.
Pour configurer l'accès à partir d'autres nœuds en dehors de localhost , utilisez ce qui suit:
* ou + . Vous devez exécuter en tant qu'administrateur (limitation du système d'exploitation)netsh :netsh http show urlaclnetsh http add urlacl url=http://[hostname]:[port]/ user=everyone listen=yeshostname et port sont les valeurs que vous utilisez dans le constructeur Lorsque vous configurez Watson.Lite pour écouter sur 127.0.0.1 , il ne répondra qu'aux demandes reçues de la machine locale.
Pour configurer l'accès à partir d'autres nœuds en dehors de la machine locale, utilisez ce qui suit:
* ou + . Vous devez exécuter en tant qu'administrateur (limitation du système d'exploitation)X509Certificate2 Veuillez vous référer au projet Test.Docker et le fichier Docker.md .
Reportez-vous à ChangeLog.md pour l'historique des versions.