You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

184 lines
6.2 KiB

11 months ago
4 years ago
11 months ago
4 years ago
11 months ago
4 years ago
11 months ago
4 years ago
4 years ago
4 years ago
  1. using Apewer.Network;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.IO;
  5. using System.Net;
  6. namespace Apewer.Web
  7. {
  8. /// <summary>用于网站的服务程序。</summary>
  9. public class HttpListenerProvider : ApiProvider<HttpListenerContext>
  10. {
  11. private HttpListenerContext context;
  12. private HttpListenerRequest request;
  13. private HttpListenerResponse response;
  14. /// <summary>HttpContext</summary>
  15. public override HttpListenerContext Context { get => context; }
  16. /// <summary>创建服务程序实例。</summary>
  17. /// <exception cref="ArgumentNullException"></exception>
  18. public HttpListenerProvider(HttpListenerContext context)
  19. {
  20. if (context == null) throw new ArgumentNullException(nameof(context));
  21. this.context = context;
  22. request = context.Request;
  23. response = context.Response;
  24. }
  25. #region Implement
  26. /// <summary>写入响应前的检查,返回错误信息。</summary>
  27. public override string PreWrite()
  28. {
  29. if (response == null) return null;
  30. // 从 Response 头中移除 Server 和 X-Powered-By 属性。
  31. var keys = new List<string>(response.Headers.AllKeys);
  32. if (keys.Contains("Server")) response.Headers.Remove("Server");
  33. if (keys.Contains("X-Powered-By")) response.Headers.Remove("X-Powered-By");
  34. return null;
  35. }
  36. /// <summary>向发送缓冲区的数据,之后停止并关闭响应流。</summary>
  37. public override void End() => End(true);
  38. #endregion
  39. #region Request
  40. /// <summary>获取 HTTP 方法。</summary>
  41. public override Network.HttpMethod GetMethod() => ApiUtility.Method(request.HttpMethod);
  42. /// <summary>获取客户端的 IP 地址。</summary>
  43. public override string GetClientIP() => request.UserHostAddress;
  44. /// <summary>获取请求的 URL。</summary>
  45. public override Uri GetUrl() => request.Url;
  46. /// <summary>获取请求的 Referrer。</summary>
  47. public override string GetReferrer() => request.UrlReferrer == null ? null : request.UrlReferrer.OriginalString;
  48. /// <summary>获取请求的头。</summary>
  49. public override HttpHeaders GetHeaders() => new HttpHeaders(request.Headers);
  50. /// <summary>获取请求的内容类型。</summary>
  51. public override string GetContentType() => request.ContentType;
  52. /// <summary>获取请求的内容长度。</summary>
  53. public override long GetContentLength() => request.ContentLength64;
  54. /// <summary>获取请求的内容。</summary>
  55. public override Stream RequestBody() => request.InputStream;
  56. #endregion
  57. #region Response
  58. /// <summary>设置 HTTP 状态。</summary>
  59. public override void SetStatus(int status, int subStatus = 0) => response.StatusCode = status;
  60. /// <summary>设置响应的头。</summary>
  61. public override string SetHeader(string name, string value)
  62. {
  63. if (response == null || string.IsNullOrEmpty(name) || string.IsNullOrEmpty(value)) return "参数无效。";
  64. try
  65. {
  66. response.AddHeader(name, value);
  67. return null;
  68. }
  69. catch (Exception ex) { return ex.Message; }
  70. }
  71. /// <summary>设置响应的缓存秒数,设置为 0 即不允许缓存。</summary>
  72. public override void SetCache(int seconds)
  73. {
  74. if (seconds > 0)
  75. {
  76. SetHeader("Cache-Control", $"public, max-age={seconds}, s-maxage={seconds}");
  77. return;
  78. }
  79. SetHeader("Cache-Control", "no-cache, no-store, must-revalidate");
  80. SetHeader("Pragma", "no-cache");
  81. }
  82. /// <summary>设置响应的缓存秒数。</summary>
  83. public override void SetContentType(string value) => response.ContentType = value;
  84. /// <summary>设置响应的内容长度。</summary>
  85. public override void SetContentLength(long value) => response.ContentLength64 = value;
  86. /// <summary>设置响应重定向。</summary>
  87. /// <remarks>响应 302 状态。</remarks>
  88. public override void SetRedirect(string location)
  89. {
  90. try { response.Redirect(location); } catch { }
  91. }
  92. /// <summary>获取 Response 流。</summary>
  93. public override Stream ResponseBody() => response.OutputStream;
  94. #endregion
  95. #region This
  96. /// <summary>停止并关闭响应流。可指定向发送缓冲区的数据。</summary>
  97. public void End(bool flush)
  98. {
  99. if (response == null) return;
  100. try { if (flush) response.OutputStream.Flush(); } catch { }
  101. try { response.Close(); } catch { }
  102. }
  103. /// <summary>获取 Cookies。</summary>
  104. public StringPairs GetCookies()
  105. {
  106. var sp = new StringPairs();
  107. if (request != null && request.Cookies != null)
  108. {
  109. for (var i = 0; i < request.Cookies.Count; i++)
  110. {
  111. try
  112. {
  113. var cookie = request.Cookies[i];
  114. var key = cookie.Name;
  115. var value = cookie.Value ?? "";
  116. sp.Add(new KeyValuePair<string, string>(key, value));
  117. }
  118. catch { }
  119. }
  120. }
  121. return sp;
  122. }
  123. /// <summary>设置响应的 Cookie。</summary>
  124. public string SetCookie(string key, string value)
  125. {
  126. if (response == null) return null;
  127. var k = key.ToTrim();
  128. var v = value.ToTrim();
  129. if (k.IsEmpty()) return "参数 Key 无效。";
  130. try
  131. {
  132. var cookie = new Cookie(k, v);
  133. var now = DateTime.Now;
  134. cookie.Expires = v.IsEmpty() ? now.AddDays(-1) : now.AddYears(1);
  135. response.SetCookie(cookie);
  136. return null;
  137. }
  138. catch (Exception ex)
  139. {
  140. return ex.Message;
  141. }
  142. }
  143. #endregion
  144. }
  145. }