利用HttpListener创建简单的HTTP服务

using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
public class HttpServer : IDisposable
{
    private const string NotFoundResponse = "<!doctype html><html><body>Resource not found</body></html>";
    private readonly HttpListener httpListener;
    private readonly CancellationTokenSource cts = new CancellationTokenSource();
    private readonly string prefixPath;

    private Task processingTask;

    public HttpServer(string listenerUriPrefix)
    {
        this.prefixPath = ParsePrefixPath(listenerUriPrefix);
        this.httpListener = new HttpListener();
        this.httpListener.Prefixes.Add(listenerUriPrefix);
    }

    private static string ParsePrefixPath(string listenerUriPrefix)
    {
        var match = Regex.Match(listenerUriPrefix, @"http://(?:[^/]*)(?:\:\d+)?/(.*)");
        if (match.Success)
        {
            return match.Groups[1].Value.ToLowerInvariant();
        }
        else
        {
            return string.Empty;
        }
    }

    public void Start()
    {
        this.httpListener.Start();
        this.processingTask = Task.Factory.StartNew(async () => await ProcessRequests(), TaskCreationOptions.LongRunning);
    }

    private async Task ProcessRequests()
    {
        while (!this.cts.IsCancellationRequested)
        {
            try
            {
                var context = await this.httpListener.GetContextAsync();
                try
                {
                    await ProcessRequest(context).ConfigureAwait(false);
                    context.Response.Close();
                }
                catch (Exception ex)
                {
                    context.Response.StatusCode = 500;
                    context.Response.StatusDescription = "Internal Server Error";
                    context.Response.Close();
                    Console.WriteLine("Error processing HTTP request\n{0}", ex);
                }
            }
            catch (ObjectDisposedException ex)
            {
                if ((ex.ObjectName == this.httpListener.GetType().FullName) && (this.httpListener.IsListening == false))
                {
                    return; // listener is closed/disposed
                }
                Console.WriteLine("Error processing HTTP request\n{0}", ex);
            }
            catch (Exception ex)
            {
                HttpListenerException httpException = ex as HttpListenerException;
                if (httpException == null || httpException.ErrorCode != 995)// IO operation aborted
                {
                    Console.WriteLine("Error processing HTTP request\n{0}", ex);
                }
            }
        }
    }

    private Task ProcessRequest(HttpListenerContext context)
    {
        if (context.Request.HttpMethod.ToUpperInvariant() != "GET")
        {
            return WriteNotFound(context);
        }

        var urlPath = context.Request.RawUrl.Substring(this.prefixPath.Length)
            .ToLowerInvariant();

        switch (urlPath)
        {
            case "/":
                if (!context.Request.Url.ToString().EndsWith("/"))
                {
                    context.Response.Redirect(context.Request.Url + "/");
                    context.Response.Close();
                    return Task.FromResult(0);
                }
                else
                {
                    return WriteString(context, "Hello World!", "text/plain");
                }
            case "/favicon.ico":
                return WriteFavIcon(context);
            case "/ping":
                return WritePong(context);
        }
        return WriteNotFound(context);
    }

    private static Task WritePong(HttpListenerContext context)
    {
        return WriteString(context, "pong", "text/plain");
    }

    private static async Task WriteFavIcon(HttpListenerContext context)
    {
        context.Response.ContentType = "image/png";
        context.Response.StatusCode = 200;
        context.Response.StatusDescription = "OK";
        using (var stream = File.Open("icon.png", FileMode.Open))
        {
            var output = context.Response.OutputStream;
            await stream.CopyToAsync(output);
        }
    }

    private static Task WriteNotFound(HttpListenerContext context)
    {
        return WriteString(context, NotFoundResponse, "text/plain", 404, "NOT FOUND");
    }

    private static async Task WriteString(HttpListenerContext context, string data, string contentType,
        int httpStatus = 200, string httpStatusDescription = "OK")
    {
        AddCORSHeaders(context.Response);
        AddNoCacheHeaders(context.Response);

        context.Response.ContentType = contentType;
        context.Response.StatusCode = httpStatus;
        context.Response.StatusDescription = httpStatusDescription;

        var acceptsGzip = AcceptsGzip(context.Request);
        if (!acceptsGzip)
        {
            using (var writer = new StreamWriter(context.Response.OutputStream, Encoding.UTF8, 4096, true))
            {
                await writer.WriteAsync(data).ConfigureAwait(false);
            }
        }
        else
        {
            context.Response.AddHeader("Content-Encoding", "gzip");
            using (GZipStream gzip = new GZipStream(context.Response.OutputStream, CompressionMode.Compress, true))
            using (var writer = new StreamWriter(gzip, Encoding.UTF8, 4096, true))
            {
                await writer.WriteAsync(data).ConfigureAwait(false);
            }
        }
    }

    private static bool AcceptsGzip(HttpListenerRequest request)
    {
        string encoding = request.Headers["Accept-Encoding"];
        if (string.IsNullOrEmpty(encoding))
        {
            return false;
        }

        return encoding.Contains("gzip");
    }

    private static void AddNoCacheHeaders(HttpListenerResponse response)
    {
        response.Headers.Add("Cache-Control", "no-cache, no-store, must-revalidate");
        response.Headers.Add("Pragma", "no-cache");
        response.Headers.Add("Expires", "0");
    }

    private static void AddCORSHeaders(HttpListenerResponse response)
    {
        response.Headers.Add("Access-Control-Allow-Origin", "*");
        response.Headers.Add("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
    }

    private void Stop()
    {
        cts.Cancel();
        if (processingTask != null && !processingTask.IsCompleted)
        {
            processingTask.Wait();
        }
        if (this.httpListener.IsListening)
        {
            this.httpListener.Stop();
            this.httpListener.Prefixes.Clear();
        }
    }

    public void Dispose()
    {
        this.Stop();
        this.httpListener.Close();
        using (this.cts) { }
        using (this.httpListener) { }
    }
}
时间: 2024-07-30 03:19:57

利用HttpListener创建简单的HTTP服务的相关文章

通过HttpListener实现简单的Http服务

使用HttpListener实现简单的Http服务 HttpListener提供一个简单的.可通过编程方式控制的 HTTP 协议侦听器.使用它可以很容易的提供一些Http服务,而无需启动IIS这类大型服务程序.使用HttpListener的方法流程很简单:主要分为以下几步 创建一个HTTP侦听器对象并初始化 添加需要监听的URI 前缀 开始侦听来自客户端的请求 处理客户端的Http请求 关闭HTTP侦听器 例如:我们要实现一个简单Http服务,进行文件的下载,或者进行一些其他的操作,例如要发送邮

使用C#创建简单的WCF服务

一.开发环境 操作系统:Windows 10 开发环境:VS2015 编程语言:C# IIS版本:10.0.0.0 二.添加WCF服务.Internet Information Services(IIS)  1.进入“控制面板”,打开“程序和功能”,点击左上角的“启用或关闭Windows功能”后,在“.NET Framework 4.6 高级服务”中的子节点选中“WCF 服务”,如下图所示: 2.再找到“Internet Information Services”,同样选中该节点,如下图所示:

Python创建简单的HTTP服务

python2中: python -m SimpleHTTPServer 80  # 默认端口是8000,目录是当前目录 如果当前文件夹有index.html文件,会默认显示该文件,否则,会以文件列表的形式显示目录下所有文件.这样已经实现了最基本的文件分享的目的 python3中: python -m http.server 80 import http.server PORT = 250 Handler = http.server.SimpleHTTPRequestHandler httpd 

通过VS创建简单的WCF服务

http://www.cnblogs.com/artech/archive/2007/09/15/893838.html http://www.topwcftutorials.net/2013/09/simple-steps-for-restful-service.html http://www.codeproject.com/Articles/571813/A-Beginners-Tutorial-on-Creating-WCF-REST-Services http://blog.csdn.n

使用idea创建简单的webservice服务

New project: 生成HelloWorld.wsdl: 配置好tomcat后还需要加入 Axis 的库: 启动后,访问http://localhost:8080/services: 点击HelloWorld (wsdl)可看到相应的信息: 原文地址:https://www.cnblogs.com/ooo0/p/11297230.html

使用Topshelf组件构建简单的Windows服务

很多时候都在讨论是否需要了解一个组件或者一个语言的底层原理这个问题,其实我个人觉得,对于这个问题,每个人都有自己的看法,个人情况不同,选择的方式也就会不同了.我个人觉得无论学习什么,都应该尝试着去了解对应的原理和源码(这里就不要急着吐槽,容我说完).对底层的了解不是为了让你写出类似的东西,让你写也不可能写的出来,重写一个就需要以此修改整个底层结构,了解底层知识只是为了让你可以在写业务代码时,选择合适的方式,以此使底层与业务层配合达到效率最佳.任何一种方式有坏有好,需要合适的选择. 如果觉得楼主以

利用navicat创建存储过程、触发器和使用游标的简单实例

创建存储过程和触发器 1.建表 首先先建两张表(users表和number表),具体设计如下图: 2.存储过程 写一个存储过程,往users表中插入数据,创建过程如下: 代码如下: BEGIN     #Routine body goes here...     declare n bigint;     set n = 201121029684;     while n <= 201121029694     do         insert into users(student_ID) v

利用SpringCloud搭建一个最简单的微服务框架

http://blog.csdn.net/caicongyang/article/details/52974406 1.微服务 微服务主要包含服务注册,服务发现,服务路由,服务配置,服务熔断,服务降级等一系列的服务,而Spring Cloud为我们提供了个一整套的服务: 本例子为你提供了最简单的一个服务发现例子,包含服务注册发现spingCloudEurekaServer.服务配置中心spingCloudConfServer.以及一个app应用springCloudApp 2.服务注册与发现 s

利用OpenShift托管Node.js Web服务进行微信公众号开发

最近写了一个微信的翻译机器人.用户只要关注该微信号,发送英文的消息,就能收到中文翻译的回复.后台是用Node.js写的,托管在OpenShift的Paas平台上.翻译过程实际上是调用微软的Bing translation API做的,代码中用到了alexu84的bing-translate和JacksonTian的wechat这两个npm模块.下面把做的过程详细说一下. 1. 微信公众号开发 首先是要到https://mp.weixin.qq.com 申请一个公众号,并申请成为开发者.目前个人只