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.

310 lines
11 KiB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. using Apewer.Network;
  2. using Apewer.Source;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Diagnostics;
  6. using System.IO;
  7. using System.Reflection;
  8. using static Apewer.Internals.ApiHelper;
  9. namespace Apewer.Web
  10. {
  11. internal class ApiProcessor
  12. {
  13. internal ApiInvoker Invoker;
  14. internal ApiEntries Entries;
  15. internal ApiProvider Provider;
  16. ApiOptions Options;
  17. Stopwatch Stopwatch;
  18. Uri Url;
  19. HttpMethod Method;
  20. ApiRequest ApiRequest;
  21. ApiResponse ApiResponse;
  22. internal ApiProcessor()
  23. {
  24. }
  25. /// <summary>执行处理程序,返回错误信息。</summary>
  26. public string Run()
  27. {
  28. if (Options == null) Options = new ApiOptions();
  29. if (Options.WithDuration)
  30. {
  31. Stopwatch = new Stopwatch();
  32. Stopwatch.Start();
  33. }
  34. var error = Flow();
  35. if (Stopwatch != null)
  36. {
  37. Stopwatch.Stop();
  38. Stopwatch = null;
  39. }
  40. return error;
  41. }
  42. string Flow()
  43. {
  44. try
  45. {
  46. // 传入字段。
  47. if (Provider == null) return "服务程序无效。";
  48. if (Invoker == null) return "调用器无效。";
  49. if (Entries == null) return "入口无效。";
  50. Options = Invoker.Options ?? new ApiOptions();
  51. Provider.Options = Options;
  52. // 检查执行的前提条件,获取 Method 和 URL。
  53. var check = Check();
  54. if (!string.IsNullOrEmpty(check)) return check;
  55. // 准备请求和响应模型。
  56. ApiRequest = GetRequest(Provider, Options, Method, Url);
  57. ApiResponse = new ApiResponse();
  58. ApiResponse.Random = ApiRequest.Random;
  59. ApiResponse.Application = ApiRequest.Application;
  60. ApiResponse.Function = ApiRequest.Function;
  61. // 调用 API。
  62. var invoke = Invoke();
  63. if (!string.IsNullOrEmpty(invoke)) return invoke;
  64. // 输出。
  65. if (Stopwatch != null)
  66. {
  67. Stopwatch.Stop();
  68. ApiResponse.Duration = Stopwatch.ElapsedMilliseconds;
  69. Stopwatch = null;
  70. }
  71. Output(Provider, Options, ApiResponse, ApiRequest, Method);
  72. return null;
  73. }
  74. catch (Exception ex)
  75. {
  76. if (Stopwatch != null)
  77. {
  78. Stopwatch.Stop();
  79. Stopwatch = null;
  80. }
  81. return ex.Message;
  82. }
  83. }
  84. string Check()
  85. {
  86. // 服务程序检查。
  87. var check = Provider.PreInvoke();
  88. if (!string.IsNullOrEmpty(check)) return check;
  89. // URL
  90. Url = Provider.GetUrl();
  91. if (Url == null) return "URL 无效。";
  92. Method = Provider.GetMethod();
  93. if (Method == HttpMethod.NULL) return "HTTP 方法无效。";
  94. if (Method == HttpMethod.OPTIONS) return null;
  95. // favicon.ico
  96. var lowerPath = TextUtility.AssureStarts(TextUtility.Lower(Url.AbsolutePath), "/");
  97. if (!Options.AllowFavIcon)
  98. {
  99. if (lowerPath.StartsWith("/favicon.ico"))
  100. {
  101. Output(Provider, Options, null, null);
  102. return "已取消对 favicon.ico 的请求。";
  103. }
  104. }
  105. // robots.txt
  106. if (!Options.AllowRobots)
  107. {
  108. if (lowerPath.StartsWith("/robots.txt"))
  109. {
  110. const string text = "User-agent: *\nDisallow: / \n";
  111. Output(Provider, Options, "text/plain", TextUtility.Bytes(text));
  112. return "已取消对 robots.txt 的请求。";
  113. }
  114. }
  115. return null;
  116. }
  117. // 寻找入口。
  118. string Invoke()
  119. {
  120. var appName = ApiRequest.Application;
  121. var funcName = ApiRequest.Function;
  122. var random = ApiRequest.Random;
  123. Invoke(Entries.Get(appName));
  124. if (Stopwatch != null) ApiResponse.Duration = Stopwatch.ElapsedMilliseconds;
  125. ApiResponse.Application = appName;
  126. ApiResponse.Function = funcName;
  127. ApiResponse.Random = random;
  128. return null;
  129. }
  130. // 创建控制器。
  131. void Invoke(ApiApplication application)
  132. {
  133. var request = ApiRequest;
  134. var response = ApiResponse;
  135. var function = null as ApiFunction;
  136. var controller = null as ApiController;
  137. // Application 无效,尝试默认控制器和枚举。
  138. if (application == null)
  139. {
  140. var @default = Options.Default;
  141. if (@default == null)
  142. {
  143. // 没有指定默认控制器,尝试枚举。
  144. response.Error("Invalid Application");
  145. if (Options.AllowEnumerate) response.Data = Enumerate(Entries.Enumerate(), Options);
  146. return;
  147. }
  148. else
  149. {
  150. // 创建默认控制器。
  151. try { controller = CreateController(@default, request, response, Options); }
  152. catch (Exception ex) { ApiUtility.Exception(response, ex.InnerException); }
  153. }
  154. }
  155. else
  156. {
  157. // 创建控制器时候会填充 Controller.Request 属性,可能导致 Request.Function 被篡改,所以在创建之前获取 Function。
  158. function = application.Get(request.Function);
  159. try { controller = CreateController(application.Type, request, response, Options); }
  160. catch (Exception ex) { ApiUtility.Exception(response, ex.InnerException); }
  161. }
  162. if (controller == null) response.Error("创建控制器实例失败。");
  163. else Invoke(controller, application, function, Options, request, response);
  164. RuntimeUtility.Dispose(controller);
  165. }
  166. // 调用 Function。
  167. static void Invoke(ApiController controller, ApiApplication application, ApiFunction function, ApiOptions options, ApiRequest request, ApiResponse response)
  168. {
  169. // 没有 ApiApplication,使用了 Options 中指定的默认控制器。
  170. if (application == null)
  171. {
  172. application = new ApiApplication();
  173. application.Independent = true;
  174. application.Hidden = true;
  175. }
  176. try
  177. {
  178. // 控制器初始化。
  179. var initializer = ApiUtility.GetInitialier(controller);
  180. var match = initializer == null ? true : initializer.Invoke(controller);
  181. if (!match) return;
  182. if (application.Independent) return;
  183. if (function != null)
  184. {
  185. var result = function.Method.Invoke(controller, ReadParameters(request, function));
  186. if (result == null || function.Returnable == null) return;
  187. var returnable = function.Returnable;
  188. // 已明确字符串类型,视为提示错误。
  189. if (returnable.Equals(typeof(string)))
  190. {
  191. var error = result as string;
  192. if (!string.IsNullOrEmpty(error)) response.Error(error);
  193. return;
  194. }
  195. // 已明确 Exception 类型,视为提示错误。
  196. if (result is Exception)
  197. {
  198. ApiUtility.Exception(response, result as Exception);
  199. return;
  200. }
  201. // 已明确 Json 类型。
  202. if (result is Json)
  203. {
  204. response.Data = result as Json;
  205. return;
  206. }
  207. // 已明确 Model 类型。
  208. if (result is ApiModel)
  209. {
  210. response.Model = result as ApiModel;
  211. return;
  212. }
  213. // 类型未知,尝试 ToJson 方法。
  214. var tojson = result as IToJson;
  215. if (tojson != null)
  216. {
  217. response.Data = tojson.ToJson();
  218. return;
  219. }
  220. // 类型未知,尝试 Record 模型。
  221. var record = result as IRecord;
  222. if (record != null)
  223. {
  224. response.Data = Json.From(record);
  225. return;
  226. }
  227. // 未知类型,尝试 Json 类型。
  228. var json = result as Json;
  229. if (json != null)
  230. {
  231. response.Data = json;
  232. return;
  233. }
  234. // 未知返回类型,无法明确输出格式,忽略。
  235. }
  236. else
  237. {
  238. // 未匹配到 Function,尝试 Default。
  239. var @default = ApiUtility.GetDefault(controller);
  240. if (@default != null)
  241. {
  242. @default.Invoke(controller);
  243. return;
  244. }
  245. // 没有执行任何 Function,尝试枚举。
  246. if (application.Hidden)
  247. {
  248. response.Error("Invalid Application");
  249. }
  250. else
  251. {
  252. response.Error("Invalid Function");
  253. if (options.AllowEnumerate) response.Data = Enumerate(application.Items, options);
  254. }
  255. }
  256. }
  257. catch (Exception exception)
  258. {
  259. if (exception == null) response.Error("发生了未定义的异常。");
  260. else ApiUtility.Exception(response, exception);
  261. }
  262. }
  263. static ApiController CreateController(Type type, ApiRequest request, ApiResponse response, ApiOptions options)
  264. {
  265. var controller = (ApiController)Activator.CreateInstance(type);
  266. ApiUtility.SetProperties(controller, request, response, options);
  267. return controller;
  268. }
  269. }
  270. }