
خادم ويب بسيط وقابل للتطوير وسريع ومتزامن لمعالجة طلبات HTTP/HTTPS المريحة ، المكتوبة في C#.
| طَرد | إصدار nuget | التنزيلات |
|---|---|---|
| واتسون | ||
| واتسون | ||
| واتسون |
شكر خاص لـ damiendennehy للسماح لنا باستخدام اسم حزمة Watson.Core في Nuget!
هذا المشروع هو جزء من مؤسسة .NET جنبًا إلى جنب مع مشاريع أخرى مثل .NET وقت التشغيل.
SendChunk يقبل الآن isFinal كعقار BooleanTest.ServerSentEventsأرغب في تقديم شكر خاص لتلك التي ساعدت في جعل Watson Webserver أفضل.
Watson هو خادم ويب يعمل فوق http.sys الأساسي داخل نظام التشغيل. تم إنشاء Watson.lite عن طريق دمج httpserverlite. لا يتمتع Watson.Lite بالاعتماد على http.sys ، ويتم تنفيذه باستخدام تطبيق TCP الذي توفره CavemantCP.
إن الاعتماد على http.sys (أو عدم وجودها) يخلق اختلافات دقيقة بين المكتبتين ، ومع ذلك ، يجب أن يكون تكوين وإدارة كل منهما متسقة.
Watson.lite أقل أداءً من Watson ، لأن تطبيق HTTP موجود في مساحة المستخدم.
localhost الارتفاع (الامتيازات الإدارية) إذا ربط IP بخلاف 127.0.0.1X509Certificate2 توجيه Watson و Watson.lite دائمًا بالترتيب التالي (تكوين باستخدام Webserver.Routes ):
.Preflight OPTIONS.PreRouting.PreAuthentication.Static - طرق ثابتة ، على سبيل المثال طريقة HTTP وعنوان URL صريح.Content - طرق خدمة الملفات ، على سبيل المثال ، دليل حيث يمكن قراءة الملفات.Parameter - الطرق التي يتم فيها تحديد المتغيرات في المسار ، على سبيل المثال /user/{id}.Dynamic - الطرق التي يتم فيها تعريف عنوان URL بتعبير منتظم.AuthenticateRequest.PostAuthentication .PreAuthentication.Default - المسار الافتراضي ؛ جميع الطلبات تذهب هنا إذا لم يتم توجيهها من قبل.PostRouting - يتم الاحتجاج دائمًا ، بشكل عام لتسجيلها والقياس عن بعد إذا كنت لا ترغب في استخدام المصادقة .PostAuthentication AuthenticateRequest عليك تعيين طرقك .Default مجموعة توجيه .PreAuthentication
كقاعدة عامة ، لا تحاول أبدًا إرسال البيانات إلى HttpResponse أثناء وجودها في طريق .PostRouting . إذا تم إرسال استجابة بالفعل ، فإن محاولة داخل .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" ) ; يدعم Watson كلا من استلام البيانات المكثفة وإرسال البيانات المكثفة (المشار إليها بواسطة 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 ;
} يدعم Watson إرسال أحداث Server-Sent. ارجع إلى Test.ServerSentEvents لتنفيذ العينة. تتولى طريقة SendEvent معالجة data: وما يلي nn إلى رسالتك.
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 :netsh http show urlaclnetsh 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 لتاريخ الإصدار.