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.

798 lines
28 KiB

3 years ago
3 years ago
1 year ago
3 years ago
2 years ago
1 year ago
2 years ago
1 year ago
3 years ago
1 year ago
3 years ago
1 year ago
3 years ago
2 years ago
1 year ago
3 years ago
2 years ago
1 year ago
2 years ago
3 years ago
3 years ago
3 years ago
1 year ago
3 years ago
2 years ago
3 years ago
2 years ago
3 years ago
1 year ago
3 years ago
2 years ago
3 years ago
2 years ago
3 years ago
2 years ago
3 years ago
2 years ago
3 years ago
2 years ago
3 years ago
2 years ago
3 years ago
2 years ago
3 years ago
2 years ago
3 years ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
3 years ago
1 year ago
3 years ago
3 years ago
2 years ago
3 years ago
2 years ago
3 years ago
1 year ago
3 years ago
1 year ago
1 year ago
3 years ago
1 year ago
1 year ago
3 years ago
3 years ago
3 years ago
1 year ago
3 years ago
1 year ago
3 years ago
1 year ago
3 years ago
1 year ago
3 years ago
1 year ago
3 years ago
1 year ago
3 years ago
2 years ago
3 years ago
1 year ago
2 years ago
3 years ago
1 year ago
3 years ago
1 year ago
3 years ago
1 year ago
3 years ago
1 year ago
3 years ago
1 year ago
3 years ago
1 year ago
3 years ago
1 year ago
3 years ago
1 year ago
3 years ago
1 year ago
3 years ago
1 year ago
3 years ago
1 year ago
3 years ago
3 years ago
3 years ago
3 years ago
1 year ago
3 years ago
2 years ago
2 years ago
3 years ago
2 years ago
3 years ago
2 years ago
3 years ago
2 years ago
3 years ago
2 years ago
3 years ago
2 years ago
3 years ago
2 years ago
3 years ago
2 years ago
2 years ago
2 years ago
2 years ago
3 years ago
1 year ago
3 years ago
1 year ago
1 year ago
3 years ago
1 year ago
1 year ago
3 years ago
2 years ago
3 years ago
  1. using Apewer.Network;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Net;
  5. using System.Reflection;
  6. using static Apewer.Web.ApiUtility;
  7. namespace Apewer.Web
  8. {
  9. internal class ApiProcessor
  10. {
  11. private ApiContext _context = null;
  12. internal ApiProcessor(ApiContext context) => _context = context ?? throw new ArgumentNullException(nameof(context));
  13. #region prepare
  14. /// <summary>执行处理程序,返回错误信息。</summary>
  15. public void Run()
  16. {
  17. var url = null as Uri;
  18. var method = HttpMethod.NULL;
  19. var response = null as ApiResponse;
  20. try
  21. {
  22. // 检查执行的前提条件,获取 Method 和 URL。
  23. var check = Check(ref method, ref url);
  24. if (!string.IsNullOrEmpty(check))
  25. {
  26. Logger.Internals.Error(typeof(ApiInvoker), check);
  27. return;
  28. }
  29. // 准备请求模型。
  30. var request = GetRequest(_context.Provider, _context.Options, method, url);
  31. _context.Request = request;
  32. // 准备响应模型。
  33. response = new ApiResponse();
  34. response.Random = request.Random;
  35. response.Application = request.Application;
  36. response.Function = request.Function;
  37. _context.Response = response;
  38. // OPTIONS
  39. if (_context.Request.Method == HttpMethod.OPTIONS)
  40. {
  41. if (!_context.Options.AllowOptions)
  42. {
  43. _context.Response.Model = new ApiTextModel("");
  44. return;
  45. }
  46. }
  47. // 中间件
  48. var middlewares = _context.Invoker.Middlewares;
  49. if (middlewares.Length > 0)
  50. {
  51. // 设置队列和回调。
  52. _mw_queue = new Queue<Type>(middlewares);
  53. _context.SetMiddlewareCallback(MiddlewareNext);
  54. // 执行。
  55. MiddlewareNext(_context);
  56. }
  57. else
  58. {
  59. // 无中间件。
  60. Route();
  61. }
  62. }
  63. catch (Exception ex)
  64. {
  65. ApiUtility.Exception(_context.Response, ex, _context.Options.WithException);
  66. var message = ex.Message();
  67. Logger.Internals.Error(typeof(ApiInvoker), message);
  68. }
  69. finally
  70. {
  71. // 输出。
  72. if (response != null)
  73. {
  74. try
  75. {
  76. response.Duration = Duration(_context.Beginning);
  77. Output(_context.Provider, _context.Options, response, null, method);
  78. }
  79. catch { }
  80. finally
  81. {
  82. RuntimeUtility.Dispose(response.Model);
  83. }
  84. }
  85. }
  86. }
  87. static string Duration(DateTime beginning)
  88. {
  89. var span = DateTime.Now - beginning;
  90. var ms = span.TotalMilliseconds;
  91. if (ms < 1000) return Math.Round(ms, 0).ToString() + "ms";
  92. if (ms < 10000) return Math.Round(ms / 1000, 2).ToString() + "s";
  93. if (ms < 60000) return Math.Round(ms / 1000, 1).ToString() + "s";
  94. return Math.Round(ms / 1000, 0).ToString() + "s";
  95. }
  96. string Check(ref HttpMethod method, ref Uri url)
  97. {
  98. // 服务程序检查。
  99. var check = _context.Provider.PreInvoke();
  100. if (!string.IsNullOrEmpty(check)) return check;
  101. // URL
  102. url = _context.Provider.GetUrl();
  103. if (url == null) return "URL 无效。";
  104. // Method
  105. method = _context.Provider.GetMethod();
  106. switch (method)
  107. {
  108. case HttpMethod.NULL:
  109. return "HTTP 方法无效。";
  110. case HttpMethod.OPTIONS:
  111. if (!_context.Options.AllowOptions) return null;
  112. break;
  113. }
  114. // favicon.ico
  115. var lowerPath = TextUtility.AssureStarts(TextUtility.Lower(url.AbsolutePath), "/");
  116. if (!_context.Options.AllowFavIcon)
  117. {
  118. if (lowerPath.StartsWith("/favicon.ico"))
  119. {
  120. Output(_context.Provider, _context.Options, null, null, null);
  121. return "已取消对 favicon.ico 的请求。";
  122. }
  123. }
  124. // robots.txt
  125. if (!_context.Options.AllowRobots)
  126. {
  127. if (lowerPath.StartsWith("/robots.txt"))
  128. {
  129. const string text = "User-agent: *\nDisallow: / \n";
  130. Output(_context.Provider, _context.Options, null, "text/plain", TextUtility.Bytes(text));
  131. return "已取消对 robots.txt 的请求。";
  132. }
  133. }
  134. return null;
  135. }
  136. #endregion
  137. #region common
  138. static Type Void = typeof(void);
  139. // 创建控制器实例
  140. static ApiController CreateController(Type type, ApiContext context)
  141. {
  142. var controller = (ApiController)Activator.CreateInstance(type);
  143. ApiUtility.SetContext(controller, context);
  144. return controller;
  145. }
  146. static void Invoke(ApiContext context, MethodInfo method, ApiParameter[] parameters)
  147. {
  148. context.MethodInfo = method;
  149. // 调用。
  150. var parametersValue = ReadParameters(context.Request, parameters);
  151. var controller = context.Controller;
  152. var returnValue = method.Invoke(controller, parametersValue);
  153. // 程序要求停止输出。
  154. var response = context.Response;
  155. if (response.StopReturn) return;
  156. // 已经有了返回模型。
  157. if (response.Model != null) return;
  158. // 没有返回类型。
  159. var returnType = method.ReturnType;
  160. if (returnType == null || returnType.Equals(Void)) return;
  161. // 已明确字符串类型。
  162. if (returnType.Equals(typeof(string)))
  163. {
  164. var textValue = returnValue as string;
  165. var textRenderer = context.Options.TextRenderer;
  166. if (textRenderer != null)
  167. {
  168. textRenderer.Invoke(context, textValue);
  169. return;
  170. }
  171. // 默认视为提示错误
  172. if (!string.IsNullOrEmpty(textValue)) response.Error(textValue);
  173. return;
  174. }
  175. // 已明确 Exception 类型,视为提示错误。
  176. if (returnValue is Exception)
  177. {
  178. ApiUtility.Exception(response, returnValue as Exception);
  179. return;
  180. }
  181. // 已明确 Json 类型。
  182. if (returnValue is Json json)
  183. {
  184. var renderer = context.Options.JsonRenderer;
  185. if (renderer != null)
  186. {
  187. renderer.Invoke(context, json);
  188. return;
  189. }
  190. // 默认设置到 data 属性。
  191. response.Data = json;
  192. return;
  193. }
  194. // 已明确 Model 类型。
  195. if (returnValue is IApiModel model)
  196. {
  197. response.Model = model;
  198. return;
  199. }
  200. // 已明确 Result 类型。
  201. if (returnValue is IActionResult result)
  202. {
  203. response.Model = result;
  204. return;
  205. }
  206. // 类型未知,尝试 ToJson 方法。
  207. if (returnValue is IToJson toJson)
  208. {
  209. var tojson = toJson.ToJson();
  210. var renderer = context.Options.JsonRenderer;
  211. if (renderer != null)
  212. {
  213. renderer.Invoke(context, tojson);
  214. return;
  215. }
  216. response.Data = tojson;
  217. return;
  218. }
  219. // 未知返回类型,尝试使用默认渲染器。
  220. var defaultRenderer = context.Options.DefaultRenderer;
  221. if (defaultRenderer != null) defaultRenderer.Invoke(context, returnValue);
  222. }
  223. #endregion
  224. #region middleware
  225. Queue<Type> _mw_queue = null;
  226. void MiddlewareNext(ApiContext context)
  227. {
  228. if (_mw_queue.Count < 1)
  229. {
  230. Route();
  231. return;
  232. }
  233. // 创建下一个中间件的实例
  234. var type = _mw_queue.Dequeue();
  235. var instance = Activator.CreateInstance(type);
  236. var middleware = instance as IApiMiddleware;
  237. if (middleware == null) throw new Exception($"类型【{type.FullName}】不是有效的中间件。");
  238. // 调用
  239. middleware.Invoke(context);
  240. }
  241. // 执行路由。
  242. void Route()
  243. {
  244. // 路由
  245. if (_context.Options.UseRoute)
  246. {
  247. var path = _context?.Request?.Url?.AbsolutePath;
  248. path = path.TrimEnd('/');
  249. var action = _context.Entries.GetAction(path);
  250. if (action != null)
  251. {
  252. _context.ApiAction = action;
  253. InvokeAction(action);
  254. return;
  255. }
  256. }
  257. // 反射
  258. if (_context.Options.UseReflection)
  259. {
  260. var appName = _context.Request.Application;
  261. var application = _context.Entries.GetApplication(appName);
  262. InvokeApplication(application);
  263. return;
  264. }
  265. // 未匹配到
  266. _context.Response.Duration = Duration(_context.Beginning);
  267. _context.Response.Model = new ApiStatusModel(404);
  268. }
  269. #endregion
  270. #region route
  271. // 执行 Action。
  272. void InvokeAction(ApiAction action)
  273. {
  274. var controller = null as ApiController;
  275. try
  276. {
  277. // 准备控制器。
  278. controller = CreateController(action.Type, _context);
  279. // 准备参数。
  280. var parameters = action.Parameters;
  281. var values = ReadParameters(_context.Request, parameters);
  282. // 调用。
  283. _context.Controller = controller;
  284. Invoke(_context, action.MethodInfo, action.Parameters);
  285. }
  286. catch (Exception ex)
  287. {
  288. if (ex.InnerException != null) ex = ex.InnerException;
  289. ApiUtility.Exception(_context.Response, ex, _context.Options.WithException);
  290. var catcher = _context.Invoker.Catcher;
  291. if (catcher != null)
  292. {
  293. try
  294. {
  295. var apiCatch = new ApiCatch(_context, ex);
  296. catcher.Invoke(apiCatch);
  297. }
  298. catch { }
  299. }
  300. }
  301. finally
  302. {
  303. RuntimeUtility.Dispose(controller);
  304. }
  305. }
  306. #endregion
  307. #region reflection
  308. // 创建控制器。
  309. void InvokeApplication(ApiApplication application)
  310. {
  311. var options = _context.Options;
  312. var entries = _context.Entries;
  313. var request = _context.Request;
  314. var response = _context.Response;
  315. // Application 无效,尝试默认控制器和枚举。
  316. if (application == null)
  317. {
  318. var @default = options.Default;
  319. if (@default == null)
  320. {
  321. // 没有指定默认控制器,尝试枚举。
  322. response.Status = "notfound";
  323. response.Message = "Not Found";
  324. if (options.AllowEnumerate) response.Data = Enumerate(entries.Applications, options);
  325. return;
  326. }
  327. else
  328. {
  329. // 创建默认控制器。
  330. var controller = null as ApiController;
  331. try
  332. {
  333. controller = CreateController(@default, _context);
  334. InvokeFunction(controller, application, null, options, request, response);
  335. }
  336. catch (Exception ex)
  337. {
  338. ApiUtility.Exception(response, ex.InnerException ?? ex);
  339. }
  340. finally
  341. {
  342. RuntimeUtility.Dispose(controller);
  343. }
  344. }
  345. }
  346. else
  347. {
  348. // 创建控制器时候会填充 Controller.Request 属性,可能导致 Request.Function 被篡改,所以在创建之前获取 Function。
  349. var function = application.GetFunction(request.Function);
  350. var controller = null as ApiController;
  351. try
  352. {
  353. controller = CreateController(application.Type, _context);
  354. InvokeFunction(controller, application, function, options, request, response);
  355. }
  356. catch (Exception ex)
  357. {
  358. ApiUtility.Exception(response, ex.InnerException ?? ex);
  359. }
  360. finally
  361. {
  362. RuntimeUtility.Dispose(controller);
  363. }
  364. }
  365. }
  366. // 调用 Function。
  367. void InvokeFunction(ApiController controller, ApiApplication application, ApiFunction function, ApiOptions options, ApiRequest request, ApiResponse response)
  368. {
  369. try
  370. {
  371. // 控制器初始化。
  372. var initializer = ApiUtility.GetInitialier(controller);
  373. var match = initializer == null ? true : initializer.Invoke(controller);
  374. if (!match) return;
  375. if (application.Independent) return;
  376. if (function != null)
  377. {
  378. // 调用 API,获取返回值。
  379. _context.Controller = controller;
  380. Invoke(_context, function.Method, function.Parameters);
  381. }
  382. else
  383. {
  384. // 未匹配到 Function,尝试 Default。
  385. var @default = ApiUtility.GetDefault(controller);
  386. if (@default != null)
  387. {
  388. @default.Invoke(controller);
  389. return;
  390. }
  391. // 没有执行任何 Function,尝试枚举。
  392. response.Status = "notfound";
  393. if (application.Hidden)
  394. {
  395. response.Message = "Not Found";
  396. }
  397. else
  398. {
  399. response.Message = "Not Found";
  400. if (options.AllowEnumerate) response.Data = Enumerate(application.Functions, options);
  401. }
  402. }
  403. }
  404. catch (Exception ex)
  405. {
  406. if (ex.InnerException != null) ex = ex.InnerException;
  407. ApiUtility.Exception(_context.Response, ex, _context.Options.WithException);
  408. var catcher = _context.Invoker.Catcher;
  409. if (catcher != null)
  410. {
  411. try
  412. {
  413. var apiCatch = new ApiCatch(_context, ex);
  414. catcher.Invoke(apiCatch);
  415. }
  416. catch { }
  417. }
  418. }
  419. }
  420. #endregion
  421. #region static
  422. internal static ApiRequest GetRequest(ApiProvider provider, ApiOptions options, HttpMethod method, Uri url)
  423. {
  424. // 创建数据对象。
  425. var request = new ApiRequest();
  426. // Http Method。
  427. request.Method = method;
  428. // 基本信息。
  429. var ip = provider.GetClientIP();
  430. var headers = provider.GetHeaders() ?? new HttpHeaders();
  431. request.Headers = headers;
  432. request.IP = ip;
  433. request.Url = url;
  434. request.Referrer = provider.GetReferrer();
  435. request.Parameters = ApiUtility.Parameters(url.Query);
  436. // Headers。
  437. request.UserAgent = ApiUtility.UserAgent(headers);
  438. request.Cookies = ParseCookies(headers) ?? new CookieCollection();
  439. // 匹配 API。
  440. var application = null as string;
  441. var function = null as string;
  442. var random = null as string;
  443. var ticket = null as string;
  444. var session = null as string;
  445. var page = null as string;
  446. // 解析 POST 请求。
  447. switch (request.Method)
  448. {
  449. case HttpMethod.PATCH:
  450. case HttpMethod.POST:
  451. case HttpMethod.PUT:
  452. var preRead = provider.PreRead();
  453. if (string.IsNullOrEmpty(preRead))
  454. {
  455. var post = null as byte[];
  456. var length = 0L;
  457. var max = options.MaxRequestBody;
  458. if (max == 0) post = new byte[0];
  459. else if (max < 0) post = provider.RequestBody().Read();
  460. else
  461. {
  462. length = provider.GetContentLength();
  463. if (length <= max) post = provider.RequestBody().Read();
  464. }
  465. length = post == null ? 0 : post.Length;
  466. if (length > 1)
  467. {
  468. request.PostData = post;
  469. if (length < 104857600)
  470. {
  471. var text = TextUtility.FromBytes(post);
  472. request.PostText = text;
  473. // 尝试解析 Json,首尾必须是“{}”或“[]”。
  474. var first = post[0];
  475. var last = post[length - 1];
  476. if ((first == 123 && last == 125) || (first == 91 && last == 93))
  477. {
  478. var json = Json.From(text);
  479. if (json != null && json.IsObject)
  480. {
  481. application = json["application"];
  482. function = json["function"];
  483. random = json["random"];
  484. ticket = json["ticket"];
  485. session = json["session"];
  486. page = json["page"];
  487. var data = json.GetProperty("data");
  488. request.PostJson = json;
  489. request.Data = data ?? Json.NewObject();
  490. }
  491. }
  492. // 尝试解析 Form,需要 application/x-www-form-urlencoded
  493. var contentType = headers.GetValue("Content-Type") ?? "";
  494. if (contentType.Contains("urlencoded")) request.Form = ApiUtility.Parameters(text);
  495. }
  496. }
  497. }
  498. break;
  499. }
  500. // 解析 URL 参数。
  501. // URL 参数的优先级应高于 URL 路径,以避免反向代理产生的路径问题。
  502. var urlParameters = ApiUtility.Parameters(request.Url.Query);
  503. if (string.IsNullOrEmpty(application)) application = urlParameters.GetValue("application");
  504. if (string.IsNullOrEmpty(function)) function = urlParameters.GetValue("function");
  505. if (string.IsNullOrEmpty(random)) random = urlParameters.GetValue("random");
  506. if (string.IsNullOrEmpty(ticket)) ticket = urlParameters.GetValue("ticket");
  507. if (string.IsNullOrEmpty(session)) session = urlParameters.GetValue("session");
  508. if (string.IsNullOrEmpty(page)) page = urlParameters.GetValue("page");
  509. // 从 Cookie 中获取 Ticket。
  510. var cookies = request.Cookies;
  511. if (string.IsNullOrEmpty(ticket)) ticket = cookies.GetValue("ticket");
  512. // 最后检查 URL 路径。
  513. var paths = (request.Url.AbsolutePath ?? "").Split('/');
  514. if (string.IsNullOrEmpty(application) && paths.Length >= 2) application = TextUtility.DecodeUrl(paths[1]);
  515. if (string.IsNullOrEmpty(function) && paths.Length >= 3) function = TextUtility.DecodeUrl(paths[2]);
  516. // 修正内容。
  517. application = TextUtility.Trim(application);
  518. function = TextUtility.Trim(function);
  519. random = TextUtility.Trim(random);
  520. ticket = TextUtility.Trim(ticket);
  521. session = TextUtility.Trim(session);
  522. page = TextUtility.Trim(page);
  523. // 设置请求:回传。
  524. request.Application = application;
  525. request.Function = function;
  526. request.Random = random;
  527. // 设置请求:不回传。
  528. request.Ticket = ticket;
  529. request.Session = session;
  530. request.Page = page;
  531. return request;
  532. }
  533. static StringPairs PrepareHeaders(ApiOptions options, ApiResponse response, ApiRequest request = null)
  534. {
  535. var merged = new StringPairs();
  536. if (options != null)
  537. {
  538. // 跨域访问。
  539. if (options.WithAccessControl)
  540. {
  541. merged.Add("Access-Control-Allow-Headers", "Content-Type");
  542. merged.Add("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
  543. merged.Add("Access-Control-Allow-Origin", "*");
  544. var maxage = options.AccessControlMaxAge;
  545. if (maxage > 0) merged.Add("Access-Control-Max-Age", maxage.ToString());
  546. if (request != null && request.Headers != null)
  547. {
  548. var @private = request.Headers.GetValue("Access-Control-Request-Private-Network");
  549. if (NumberUtility.Boolean(@private)) merged.Add("Access-Control-Allow-Private-Network", "true");
  550. }
  551. }
  552. // Content-Type 检查。
  553. if (options.WithContentTypeOptions)
  554. {
  555. merged.Add("X-Content-Type-Options", "nosniff");
  556. }
  557. // 用于客户端,当前页面使用 HTTPS 时,将资源升级为 HTTPS。
  558. if (options.UpgradeHttps)
  559. {
  560. merged.Add("Content-Security-Policy", "upgrade-insecure-requests");
  561. }
  562. // 包含 API 的处理时间。
  563. if (options.WithDuration && response != null)
  564. {
  565. if (response.Duration.NotEmpty()) merged.Add("Duration", response.Duration);
  566. }
  567. }
  568. if (response != null)
  569. {
  570. // Cookies。
  571. var setCookies = SetCookie(response.Cookies);
  572. if (setCookies != null)
  573. {
  574. foreach (var value in setCookies) merged.Add("Set-Cookie", value);
  575. }
  576. // 自定义头。
  577. var headers = response.Headers;
  578. if (headers != null)
  579. {
  580. foreach (var header in headers)
  581. {
  582. var key = TextUtility.Trim(header.Name);
  583. if (string.IsNullOrEmpty(key)) continue;
  584. var value = header.Value;
  585. if (string.IsNullOrEmpty(value)) continue;
  586. merged.Add(key, value);
  587. }
  588. }
  589. }
  590. return merged;
  591. }
  592. internal void Output(ApiProvider provider, ApiOptions options, ApiResponse response, string type, byte[] bytes)
  593. {
  594. var preWrite = provider.PreWrite();
  595. if (!string.IsNullOrEmpty(preWrite)) return;
  596. if (response != null)
  597. {
  598. var responsePreOutput = response.PreOutput;
  599. if (responsePreOutput != null)
  600. {
  601. var @continue = responsePreOutput.Invoke(_context);
  602. if (!@continue) return;
  603. }
  604. }
  605. var invokerPreOutput = _context.Invoker.PreOutput;
  606. if (invokerPreOutput != null)
  607. {
  608. var @continue = invokerPreOutput.Invoke(_context);
  609. if (!@continue) return;
  610. }
  611. var optionsPreOutput = _context.Options.PreOutput;
  612. if (optionsPreOutput != null)
  613. {
  614. var @continue = optionsPreOutput.Invoke(_context);
  615. if (!@continue) return;
  616. }
  617. var headers = PrepareHeaders(options, response);
  618. foreach (var header in headers) provider.SetHeader(header.Key, header.Value);
  619. provider.SetCache(0);
  620. provider.SetContentType(string.IsNullOrEmpty(type) ? "application/octet-stream" : type);
  621. var length = bytes == null ? 0 : bytes.Length;
  622. provider.SetContentLength(length);
  623. if (length > 0) provider.ResponseBody().Write(bytes, 0, bytes.Length);
  624. provider.Sent();
  625. }
  626. internal void Output(ApiProvider provider, ApiOptions options, ApiResponse response, ApiRequest request, HttpMethod method)
  627. {
  628. var preWrite = provider.PreWrite();
  629. if (!string.IsNullOrEmpty(preWrite)) return;
  630. if (response != null)
  631. {
  632. var responsePreOutput = response.PreOutput;
  633. if (responsePreOutput != null)
  634. {
  635. var @continue = responsePreOutput.Invoke(_context);
  636. if (!@continue) return;
  637. }
  638. }
  639. var invokerPreOutput = _context.Invoker.PreOutput;
  640. if (invokerPreOutput != null)
  641. {
  642. var @continue = invokerPreOutput.Invoke(_context);
  643. if (!@continue) return;
  644. }
  645. var optionsPreOutput = _context.Options.PreOutput;
  646. if (optionsPreOutput != null)
  647. {
  648. var @continue = optionsPreOutput.Invoke(_context);
  649. if (!@continue) return;
  650. }
  651. // 设置头。
  652. var headers = PrepareHeaders(options, response, request);
  653. foreach (var header in headers) provider.SetHeader(header.Key, header.Value);
  654. // 自定义模型
  655. var model = response.Model as IApiModel;
  656. var result = response.Model as IActionResult;
  657. if (model != null)
  658. {
  659. try
  660. {
  661. model.Output(_context);
  662. }
  663. catch (Exception ex)
  664. {
  665. Logger.Internals.Exception(ex, model);
  666. }
  667. RuntimeUtility.Dispose(model);
  668. return;
  669. }
  670. else if (result != null)
  671. {
  672. try
  673. {
  674. result.ExecuteResult(_context);
  675. }
  676. catch (Exception ex)
  677. {
  678. Logger.Internals.Exception(ex, result);
  679. }
  680. RuntimeUtility.Dispose(result);
  681. return;
  682. }
  683. var text = ApiUtility.ToJson(response, options);
  684. var bytes = TextUtility.Bytes(text);
  685. provider.SetCache(0);
  686. provider.SetContentType("text/json; charset=utf-8");
  687. provider.SetContentLength(bytes.Length);
  688. var stream = provider.ResponseBody();
  689. if (stream != null && stream.CanWrite) stream.Write(bytes, 0, bytes.Length);
  690. provider.Sent();
  691. }
  692. #endregion
  693. }
  694. }