
C#로 작성된 편안한 HTTP/HTTPS 요청을 처리하기위한 간단하고 확장 가능하며 빠른 비동기 웹 서버.
| 패키지 | 너겟 버전 | 다운로드 |
|---|---|---|
| 왓슨 | ||
| Watson.lite | ||
| Watson.core |
Nuget에서 Watson.Core 패키지 이름을 사용할 수 있도록 @damiendennehy에게 특별한 감사를드립니다!
이 프로젝트는 .NET 런타임과 같은 다른 프로젝트와 함께 .NET Foundation의 일부입니다.
SendChunk 이제 isFinal Boolean 속성으로 받아들입니다.Test.ServerSentEvents 프로젝트 포함Watson Webserver를 더 좋게 만드는 데 도움이 된 사람들에게 특별한 감사를 표하고 싶습니다.
Watson은 운영 체제 내에서 기본 http.sys 위에 작동하는 웹 서버입니다. Watson.lite는 httpserverlite를 병합하여 만들어졌습니다. Watson.lite는 http.sys 에 의존하지 않으며 CavemantCP에서 제공하는 TCP 구현을 사용하여 구현됩니다.
http.sys (또는 그 부족)에 대한 의존성은 두 라이브러리 사이에 미묘한 차이를 만들지 만 각 구성과 관리는 일관성이 있어야합니다.
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 경로에 변수가 지정되는 경로 (예 : /user/{id}.Dynamic URL이 정규 표현식으로 정의되는 경로.AuthenticateRequest 무분별한 경로와 인증 된 경로 사이의 경계 경로.PostAuthentication .PreAuthentication 과 동일한 구조를 가진 라우팅 그룹.Default 기본 경로; 모든 요청은 이전에 라우팅되지 않으면 여기에갑니다.PostRouting 항상 로깅 및 원격 측정을 위해 항상 호출됩니다 인증을 사용하지 않으려면 .PreAuthentication rounding 그룹에 경로를 매핑해야합니다 (기술적으로는 .PostAuthentication 또는 .Default 에 배치 될 수 있지만 AuthenticateRequest 메소드가 null이라고 가정 할 수 있습니다.
일반적으로 .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" ) ; 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은 서버 분할 이벤트 전송을 지원합니다. 샘플 구현은 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 명령을 사용하여 운영 체제 내에서 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를 참조하십시오.