65.9K
CodeProject 正在变化。 阅读更多。
Home

在 500 行以内构建一个微型 Web 服务器

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.88/5 (31投票s)

2004年10月19日

CPOL

3分钟阅读

viewsIcon

135827

downloadIcon

6006

这个微型 Web 服务器可以被需要提供专用网页的应用程序托管。

引言

最初,我对编写一个简单的 Web 服务器需要做什么很感兴趣。但随着我的进展,我意识到一个微型 Web 服务器对于许多需要提供专用网页的应用程序来说非常有用,而且编写 ASP.NET 应用程序的开销是不必要的(或者无法托管 ASP.NET 的地方)。

一个很好的例子是新闻聚合器,它提供一个包含当前新闻源的单一页面。这个项目就包含一个这样的例子。

更新(2013 年 7 月):根据要求,我添加了对 POST 命令的处理。

Using the Code

应用程序的核心是 TinyServer 类。这个类提供了一个简单的 Web 服务器,仅支持 GET 请求(没有表单),并从目录中提供网页。

要运行示例 Web 服务器,您需要构建 WebServer 项目并配置其设置:

WebRoot     : "E:\src\DotNet\WebServer\root"    <!-- location of the web pages to serve -->
DefaultPage :"default.html"                     <!-- name of the default page -->
TemplatePath: "E:\src\DotNet\WebServer\html"    <!-- location of special templates -->
Port        : 81"                               <!-- Port to server on -->
LogFile     : ""                                <!-- filepath, set to "" for console logging -->
LogLevel    : "All"                             <!--All, Warning, Error, None -->

一旦 WebServer 应用程序启动,它会实例化 TinyServer 并调用 Run()。这会在一个单独的线程中启动服务器。调用 Stop() 会终止该线程。

构建您自己的 Web 服务器

很可能,您想构建自己的此 Web 服务器版本。您需要继承 TinyServer 然后重写必要的函数。最重要的要重写的方法是 doGet()。在此方法中,您可以询问 GET 命令并返回任何必要的内容。

这是处理 GET 命令的默认实现

protected virtual void doGet(string argument)
{
  string url = getUrl(argument);
  if (url.StartsWith("/"))
    url = url.Substring(1);
  if (url.Length == 0)
    url = defaultPageName;
    
  string path = Path.Combine(webRootPath, url);
  if (File.Exists(path))
  {
    sendOk();
    sendfile(path);
  }
  else
    sendError(404, "File Not Found");
}

要处理 POST 命令,有一个 doPost 函数可以重写。目前,它做得很少

protected virtual void doPost(string argument, string Content)
{
   log(LogKind.Informational, "Post Data: '{0}'", Content);
   sendOk(); 
}

如您所见,post 的内容可用作 string

要实现您的版本,可以使用许多实用函数

  • string getUrl(string argument) 接受 doGet 的命令参数并提取 URL
  • string [] urlArgs 返回 URL 之后的参数列表
  • sendOK() 发送 OK 标头;在发送任何 HTML 之前,这是必要的
  • sendError(int errornr, string errorMsg) 发送错误而不是 OK
  • sendString(string) 发送一条消息
  • sendFile(path) 发送整个文件
  • sendTemplate (templateName) 发送模板目录中的文件

RssAggregator 示例应用程序

为了演示这种能力,我编写了一个简单的新闻聚合器,它定期从源下载 RSS 提要。

RssAggregator 做两件事

  1. 下载并保持更新选定的 RSS 提要列表
  2. 运行一个 Web 服务器,该服务器返回一个包含提要详细信息的网页

第一部分使用由 smallguy78 创建的 RssReader 类。它在自己的线程中运行,并且一旦当前副本超过一小时就会下载提要。

第二部分由一个名为 AggServerTinyServer 子类实现。AggServer 仅返回一个包含新闻提要摘要和文章链接的页面。所以 doGet() 相当简单

protected override void doGet(string argument)
{
  this.sendOk();
  this.sendString(writeLinkPage());
}

创建网页的智能在于 writeLinkPage() 方法,该方法又依赖于辅助函数 RssReader.CreateHtml()。整个示例(不包括 RssReader)仅需要 80 行代码。

关注点

感谢 smallguy78,我使用了他的 RssReader 代码。您可以在此 RSS 阅读器文章中找到更多相关信息。

© . All rights reserved.