- ブラウザからのリクエストに応えられるようにします
-
次の要求には、index.htmlを返すようにします
localhost GET /http://localhost/
-
次の要求には、favicon.icoを返すようにします
localhost GET /http://localhost/favicon.ico
ディレクトリ構造
- 以下のディレクトリ構造を用意してください
SimpleWebServer
├── Program.cs
├── Server.cs
├── ContentLoader.cs
└── Website
├── Pages
| ├── index.html <--内容は何でもOK
| └── page1.html <--内容は何でもOK
└── Images
└── favicon.ico <--内容は何でもOK
実装
Server.cs
- ブラウザからのリクエストへの応答をContentLoaderから受け取るようにします
private void Respond(HttpListenerContext context)
{
var req = context.Request;
var res = context.Response;
// リクエストの内容をlogに残す
Console.Out.WriteLine($"{req.UserHostName} {req.HttpMethod} /{req.Url.AbsoluteUri}");
- var message = "hello browser";
- var bytes = Encoding.UTF8.GetBytes(message);
+ var content = ContentLoader.Load(req);
+ if (content != null)
+ {
res.StatusCode = (int)HttpStatusCode.OK;
- res.ContentType = "text/html";
+ res.ContentType = content.ContentType;
res.ContentEncoding = Encoding.UTF8;
- res.ContentLength64 = bytes.Length;
- res.OutputStream.Write(bytes, 0, bytes.Length);
+ res.ContentLength64 = content.Bytes.Length;
+ res.OutputStream.Write(content.Bytes, 0, content.Bytes.Length);
res.OutputStream.Close();
+ }
}
}
ContentLoader
- ブラウザが要求しているデータの種類をURLの拡張子から判別
- サーバ上のデータのpathをデータの種類とURLから判別
- データをbyte列として読み込む
- byte列を含む必要な情報をContentクラスに入れて返す
データ種類 | 拡張子 | データのあるフォルダ |
---|---|---|
ページ内容 | html | { Projectフォルダ } / Website / Pages |
アイコン | ico | { Projectフォルダ } / Website / Images |
using System;
using System.IO;
using System.Text;
namespace SimpleWebServer
{
class Content
{
public string ContentType { get; set; }
public Encoding ContentEncoding { get; set; }
public byte[] Bytes { get; set; }
}
class ContentLoader
{
static readonly string RootDir;
static ContentLoader()
{
RootDir = Path.Combine(
Directory.GetParent(Environment.CurrentDirectory).Parent.FullName,
"Website");
}
public static Content Load(HttpListenerRequest req)
{
var url = req.Url.AbsolutePath;
var extension = Path.GetExtension(url).Trim('.');
switch (extension)
{
case "":
case "html":
return LoadPage(url);
case "ico":
return LoadImage(url, extension);
default:
throw new Exception("unsupported content type");
}
}
static Content LoadPage(string url)
{
var page = (url == "/") ? "index.html" : url;
if (!page.EndsWith(".html"))
page += ".html";
var path = Path.Combine(RootDir, "Pages", page.Trim('/'));
if (!File.Exists(path))
return null;
var text = File.ReadAllText(path);
return new Content
{
ContentType = "text/html",
ContentEncoding = Encoding.UTF8,
Bytes = Encoding.UTF8.GetBytes(text),
};
}
static Content LoadImage(string url, string extension)
{
var path = Path.Combine(RootDir, "Images", url.Trim('/'));
if (!File.Exists(path))
return null;
using (var fStream = new FileStream(path, FileMode.Open, FileAccess.Read))
using (var br = new BinaryReader(fStream))
{
return new Content
{
ContentType = @"image/{extension}",
Bytes = br.ReadBytes((int)fStream.Length),
};
}
}
}
}
動作確認
-
以下の2つのアドレスを打って、正しくページが表示されること
- localhost
- localhost/page1
-
タブの左側にfaviconが表示されること
次回
- 「localhost/hogehoge」などの適当なアドレスを打つと、エラーが表示されてしまうので、「ページが存在しません」ページへredirectするようにします