利用HttpListener創建簡單的HTTP服務

来源:http://www.cnblogs.com/binking338/archive/2016/04/07/5364854.html
-Advertisement-
Play Games

using System; using System.Collections.Generic; using System.IO; using System.IO.Compression; using System.Linq; using System.Net; using System.Reflec... ...


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) { }
    }
}

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 有一段時間沒有接著微信的主題繼續介紹裡面的功能模塊了,這段時間來,微信也做了不少的變化改動,針對這些特性我全面核對了一下相關的微信公眾號和企業號的介面,對原有的微信API和系統管理做了全面的更新,本隨筆以及後面的隨筆就是基於這個工作上的總結,以期把微信涉及的功能模塊,都使用C#實現的方式來介紹。本隨 ...
  • 研究ing 待續。。。 ...
  • 前言 本文主要來學習記錄前三個建議。 建議1、正確操作字元串 建議2、使用預設轉型方法 建議3、區別對待強制轉換與as和is 其中有很多需要理解的東西,有些地方可能理解的不太到位,還望指正。 建議1、正確操作字元串 字元串應該是所有編程語言中使用最頻繁的一種基礎數據類型。如果使用不慎,我們就會為一次 ...
  • 前段時間遇到了需要禁用刷新的需求,f5按鈕就不說了,簡單的js就能把它禁用,但是工具條上的刷新按鈕卻傻傻乾不掉。 如果簡單的在刷新時重新載入畫面,通過window.location.href="url"可以很容易的實現,但是需求是要求在刷新時什麼都不做,保留畫面的狀態,這下子可就複雜化了。 asp. ...
  • Sql Server清理緩存代碼 需要較高級別的許可權 該代碼只有在登錄sql server的用戶名具有sysadmin許可權的時候才可以使用 設置的方式:安全性=》登錄名=》登錄名右鍵=》屬性=》伺服器角色=》選項(sysadmin)=》確定 之後,代碼在代碼裡面也可以執行了! ...
  • 1.模型建立,在模型上類上添加System.ComponentModel.DataAnnotations驗證屬性 ~~~C public class Product { public int Id { get; set; } [Required] public string Name { get; ...
  • 這個問題答案選至《C#入門經典》 如果方法具有返回類型,那就可以作為表達式的一部分: x=Manipulate(y,z); 如果沒有給部分方法提供實現代碼,編譯器就會在使用該方法的所有地方刪除該方法。在上面的代碼中,這會使x的結果變得模糊,因為Manipulate()方法沒有替代方法,如果沒有這個方 ...
  • 在UWP中引入了漢堡菜單,我們先看下效果圖 菜單項 XAML 添加菜單項數據源 漢堡按鈕切換SplitView收起摺疊狀態 SplitView常用屬性 CompactPaneLength 設置SplitView收起的長度 OpenPaneLength 設置SplitView打開的長度 Display ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...