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.

808 lines
29 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<ApiMiddleware>(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<ApiMiddleware> _mw_queue = null;
  226. void MiddlewareNext(ApiContext context)
  227. {
  228. if (_mw_queue.Count < 1)
  229. {
  230. Route();
  231. return;
  232. }
  233. // 创建下一个中间件的实例
  234. var middleware = _mw_queue.Dequeue();
  235. if (middleware.Type != null)
  236. {
  237. var instance = Activator.CreateInstance(middleware.Type) as IApiMiddleware;
  238. if (instance == null) throw new Exception($"类型【{middleware.Type.FullName}】不是有效的中间件。");
  239. // 调用
  240. instance.Invoke(context);
  241. }
  242. else if (middleware.Callback != null)
  243. {
  244. middleware.Callback.Invoke(context, () => MiddlewareNext(context));
  245. }
  246. else
  247. {
  248. MiddlewareNext(context);
  249. }
  250. }
  251. // 执行路由。
  252. void Route()
  253. {
  254. // 路由
  255. if (_context.Options.UseRoute)
  256. {
  257. var path = _context?.Request?.Url?.AbsolutePath;
  258. path = path.TrimEnd('/');
  259. var action = _context.Entries.GetAction(path);
  260. if (action != null)
  261. {
  262. _context.ApiAction = action;
  263. InvokeAction(action);
  264. return;
  265. }
  266. }
  267. // 反射
  268. if (_context.Options.UseReflection)
  269. {
  270. var appName = _context.Request.Application;
  271. var application = _context.Entries.GetApplication(appName);
  272. InvokeApplication(application);
  273. return;
  274. }
  275. // 未匹配到
  276. _context.Response.Duration = Duration(_context.Beginning);
  277. _context.Response.Model = new ApiStatusModel(404);
  278. }
  279. #endregion
  280. #region route
  281. // 执行 Action。
  282. void InvokeAction(ApiAction action)
  283. {
  284. var controller = null as ApiController;
  285. try
  286. {
  287. // 准备控制器。
  288. controller = CreateController(action.Type, _context);
  289. // 准备参数。
  290. var parameters = action.Parameters;
  291. var values = ReadParameters(_context.Request, parameters);
  292. // 调用。
  293. _context.Controller = controller;
  294. Invoke(_context, action.MethodInfo, action.Parameters);
  295. }
  296. catch (Exception ex)
  297. {
  298. if (ex.InnerException != null) ex = ex.InnerException;
  299. ApiUtility.Exception(_context.Response, ex, _context.Options.WithException);
  300. var catcher = _context.Invoker.Catcher;
  301. if (catcher != null)
  302. {
  303. try
  304. {
  305. var apiCatch = new ApiCatch(_context, ex);
  306. catcher.Invoke(apiCatch);
  307. }
  308. catch { }
  309. }
  310. }
  311. finally
  312. {
  313. RuntimeUtility.Dispose(controller);
  314. }
  315. }
  316. #endregion
  317. #region reflection
  318. // 创建控制器。
  319. void InvokeApplication(ApiApplication application)
  320. {
  321. var options = _context.Options;
  322. var entries = _context.Entries;
  323. var request = _context.Request;
  324. var response = _context.Response;
  325. // Application 无效,尝试默认控制器和枚举。
  326. if (application == null)
  327. {
  328. var @default = options.Default;
  329. if (@default == null)
  330. {
  331. // 没有指定默认控制器,尝试枚举。
  332. response.Status = "notfound";
  333. response.Message = "Not Found";
  334. if (options.AllowEnumerate) response.Data = Enumerate(entries.Applications, options);
  335. return;
  336. }
  337. else
  338. {
  339. // 创建默认控制器。
  340. var controller = null as ApiController;
  341. try
  342. {
  343. controller = CreateController(@default, _context);
  344. InvokeFunction(controller, application, null, options, request, response);
  345. }
  346. catch (Exception ex)
  347. {
  348. ApiUtility.Exception(response, ex.InnerException ?? ex);
  349. }
  350. finally
  351. {
  352. RuntimeUtility.Dispose(controller);
  353. }
  354. }
  355. }
  356. else
  357. {
  358. // 创建控制器时候会填充 Controller.Request 属性,可能导致 Request.Function 被篡改,所以在创建之前获取 Function。
  359. var function = application.GetFunction(request.Function);
  360. var controller = null as ApiController;
  361. try
  362. {
  363. controller = CreateController(application.Type, _context);
  364. InvokeFunction(controller, application, function, options, request, response);
  365. }
  366. catch (Exception ex)
  367. {
  368. ApiUtility.Exception(response, ex.InnerException ?? ex);
  369. }
  370. finally
  371. {
  372. RuntimeUtility.Dispose(controller);
  373. }
  374. }
  375. }
  376. // 调用 Function。
  377. void InvokeFunction(ApiController controller, ApiApplication application, ApiFunction function, ApiOptions options, ApiRequest request, ApiResponse response)
  378. {
  379. try
  380. {
  381. // 控制器初始化。
  382. var initializer = ApiUtility.GetInitialier(controller);
  383. var match = initializer == null ? true : initializer.Invoke(controller);
  384. if (!match) return;
  385. if (application.Independent) return;
  386. if (function != null)
  387. {
  388. // 调用 API,获取返回值。
  389. _context.Controller = controller;
  390. Invoke(_context, function.Method, function.Parameters);
  391. }
  392. else
  393. {
  394. // 未匹配到 Function,尝试 Default。
  395. var @default = ApiUtility.GetDefault(controller);
  396. if (@default != null)
  397. {
  398. @default.Invoke(controller);
  399. return;
  400. }
  401. // 没有执行任何 Function,尝试枚举。
  402. response.Status = "notfound";
  403. if (application.Hidden)
  404. {
  405. response.Message = "Not Found";
  406. }
  407. else
  408. {
  409. response.Message = "Not Found";
  410. if (options.AllowEnumerate) response.Data = Enumerate(application.Functions, options);
  411. }
  412. }
  413. }
  414. catch (Exception ex)
  415. {
  416. if (ex.InnerException != null) ex = ex.InnerException;
  417. ApiUtility.Exception(_context.Response, ex, _context.Options.WithException);
  418. var catcher = _context.Invoker.Catcher;
  419. if (catcher != null)
  420. {
  421. try
  422. {
  423. var apiCatch = new ApiCatch(_context, ex);
  424. catcher.Invoke(apiCatch);
  425. }
  426. catch { }
  427. }
  428. }
  429. }
  430. #endregion
  431. #region static
  432. internal static ApiRequest GetRequest(ApiProvider provider, ApiOptions options, HttpMethod method, Uri url)
  433. {
  434. // 创建数据对象。
  435. var request = new ApiRequest();
  436. // Http Method。
  437. request.Method = method;
  438. // 基本信息。
  439. var ip = provider.GetClientIP();
  440. var headers = provider.GetHeaders() ?? new HttpHeaders();
  441. request.Headers = headers;
  442. request.IP = ip;
  443. request.Url = url;
  444. request.Referrer = provider.GetReferrer();
  445. request.Parameters = ApiUtility.Parameters(url.Query);
  446. // Headers。
  447. request.UserAgent = ApiUtility.UserAgent(headers);
  448. request.Cookies = ParseCookies(headers) ?? new CookieCollection();
  449. // 匹配 API。
  450. var application = null as string;
  451. var function = null as string;
  452. var random = null as string;
  453. var ticket = null as string;
  454. var session = null as string;
  455. var page = null as string;
  456. // 解析 POST 请求。
  457. switch (request.Method)
  458. {
  459. case HttpMethod.PATCH:
  460. case HttpMethod.POST:
  461. case HttpMethod.PUT:
  462. var preRead = provider.PreRead();
  463. if (string.IsNullOrEmpty(preRead))
  464. {
  465. var post = null as byte[];
  466. var length = 0L;
  467. var max = options.MaxRequestBody;
  468. if (max == 0) post = new byte[0];
  469. else if (max < 0) post = provider.RequestBody().Read();
  470. else
  471. {
  472. length = provider.GetContentLength();
  473. if (length <= max) post = provider.RequestBody().Read();
  474. }
  475. length = post == null ? 0 : post.Length;
  476. if (length > 1)
  477. {
  478. request.PostData = post;
  479. if (length < 104857600)
  480. {
  481. var text = TextUtility.FromBytes(post);
  482. request.PostText = text;
  483. // 尝试解析 Json,首尾必须是“{}”或“[]”。
  484. var first = post[0];
  485. var last = post[length - 1];
  486. if ((first == 123 && last == 125) || (first == 91 && last == 93))
  487. {
  488. var json = Json.From(text);
  489. if (json != null && json.IsObject)
  490. {
  491. application = json["application"];
  492. function = json["function"];
  493. random = json["random"];
  494. ticket = json["ticket"];
  495. session = json["session"];
  496. page = json["page"];
  497. var data = json.GetProperty("data");
  498. request.PostJson = json;
  499. request.Data = data ?? Json.NewObject();
  500. }
  501. }
  502. // 尝试解析 Form,需要 application/x-www-form-urlencoded
  503. var contentType = headers.GetValue("Content-Type") ?? "";
  504. if (contentType.Contains("urlencoded")) request.Form = ApiUtility.Parameters(text);
  505. }
  506. }
  507. }
  508. break;
  509. }
  510. // 解析 URL 参数。
  511. // URL 参数的优先级应高于 URL 路径,以避免反向代理产生的路径问题。
  512. var urlParameters = ApiUtility.Parameters(request.Url.Query);
  513. if (string.IsNullOrEmpty(application)) application = urlParameters.GetValue("application");
  514. if (string.IsNullOrEmpty(function)) function = urlParameters.GetValue("function");
  515. if (string.IsNullOrEmpty(random)) random = urlParameters.GetValue("random");
  516. if (string.IsNullOrEmpty(ticket)) ticket = urlParameters.GetValue("ticket");
  517. if (string.IsNullOrEmpty(session)) session = urlParameters.GetValue("session");
  518. if (string.IsNullOrEmpty(page)) page = urlParameters.GetValue("page");
  519. // 从 Cookie 中获取 Ticket。
  520. var cookies = request.Cookies;
  521. if (string.IsNullOrEmpty(ticket)) ticket = cookies.GetValue("ticket");
  522. // 最后检查 URL 路径。
  523. var paths = (request.Url.AbsolutePath ?? "").Split('/');
  524. if (string.IsNullOrEmpty(application) && paths.Length >= 2) application = TextUtility.DecodeUrl(paths[1]);
  525. if (string.IsNullOrEmpty(function) && paths.Length >= 3) function = TextUtility.DecodeUrl(paths[2]);
  526. // 修正内容。
  527. application = TextUtility.Trim(application);
  528. function = TextUtility.Trim(function);
  529. random = TextUtility.Trim(random);
  530. ticket = TextUtility.Trim(ticket);
  531. session = TextUtility.Trim(session);
  532. page = TextUtility.Trim(page);
  533. // 设置请求:回传。
  534. request.Application = application;
  535. request.Function = function;
  536. request.Random = random;
  537. // 设置请求:不回传。
  538. request.Ticket = ticket;
  539. request.Session = session;
  540. request.Page = page;
  541. return request;
  542. }
  543. static StringPairs PrepareHeaders(ApiOptions options, ApiResponse response, ApiRequest request = null)
  544. {
  545. var merged = new StringPairs();
  546. if (options != null)
  547. {
  548. // 跨域访问。
  549. if (options.WithAccessControl)
  550. {
  551. merged.Add("Access-Control-Allow-Headers", "Content-Type");
  552. merged.Add("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
  553. merged.Add("Access-Control-Allow-Origin", "*");
  554. var maxage = options.AccessControlMaxAge;
  555. if (maxage > 0) merged.Add("Access-Control-Max-Age", maxage.ToString());
  556. if (request != null && request.Headers != null)
  557. {
  558. var @private = request.Headers.GetValue("Access-Control-Request-Private-Network");
  559. if (NumberUtility.Boolean(@private)) merged.Add("Access-Control-Allow-Private-Network", "true");
  560. }
  561. }
  562. // Content-Type 检查。
  563. if (options.WithContentTypeOptions)
  564. {
  565. merged.Add("X-Content-Type-Options", "nosniff");
  566. }
  567. // 用于客户端,当前页面使用 HTTPS 时,将资源升级为 HTTPS。
  568. if (options.UpgradeHttps)
  569. {
  570. merged.Add("Content-Security-Policy", "upgrade-insecure-requests");
  571. }
  572. // 包含 API 的处理时间。
  573. if (options.WithDuration && response != null)
  574. {
  575. if (response.Duration.NotEmpty()) merged.Add("Duration", response.Duration);
  576. }
  577. }
  578. if (response != null)
  579. {
  580. // Cookies。
  581. var setCookies = SetCookie(response.Cookies);
  582. if (setCookies != null)
  583. {
  584. foreach (var value in setCookies) merged.Add("Set-Cookie", value);
  585. }
  586. // 自定义头。
  587. var headers = response.Headers;
  588. if (headers != null)
  589. {
  590. foreach (var header in headers)
  591. {
  592. var key = TextUtility.Trim(header.Name);
  593. if (string.IsNullOrEmpty(key)) continue;
  594. var value = header.Value;
  595. if (string.IsNullOrEmpty(value)) continue;
  596. merged.Add(key, value);
  597. }
  598. }
  599. }
  600. return merged;
  601. }
  602. internal void Output(ApiProvider provider, ApiOptions options, ApiResponse response, string type, byte[] bytes)
  603. {
  604. var preWrite = provider.PreWrite();
  605. if (!string.IsNullOrEmpty(preWrite)) return;
  606. if (response != null)
  607. {
  608. var responsePreOutput = response.PreOutput;
  609. if (responsePreOutput != null)
  610. {
  611. var @continue = responsePreOutput.Invoke(_context);
  612. if (!@continue) return;
  613. }
  614. }
  615. var invokerPreOutput = _context.Invoker.PreOutput;
  616. if (invokerPreOutput != null)
  617. {
  618. var @continue = invokerPreOutput.Invoke(_context);
  619. if (!@continue) return;
  620. }
  621. var optionsPreOutput = _context.Options.PreOutput;
  622. if (optionsPreOutput != null)
  623. {
  624. var @continue = optionsPreOutput.Invoke(_context);
  625. if (!@continue) return;
  626. }
  627. var headers = PrepareHeaders(options, response);
  628. foreach (var header in headers) provider.SetHeader(header.Key, header.Value);
  629. provider.SetCache(0);
  630. provider.SetContentType(string.IsNullOrEmpty(type) ? "application/octet-stream" : type);
  631. var length = bytes == null ? 0 : bytes.Length;
  632. provider.SetContentLength(length);
  633. if (length > 0) provider.ResponseBody().Write(bytes, 0, bytes.Length);
  634. provider.Sent();
  635. }
  636. internal void Output(ApiProvider provider, ApiOptions options, ApiResponse response, ApiRequest request, HttpMethod method)
  637. {
  638. var preWrite = provider.PreWrite();
  639. if (!string.IsNullOrEmpty(preWrite)) return;
  640. if (response != null)
  641. {
  642. var responsePreOutput = response.PreOutput;
  643. if (responsePreOutput != null)
  644. {
  645. var @continue = responsePreOutput.Invoke(_context);
  646. if (!@continue) return;
  647. }
  648. }
  649. var invokerPreOutput = _context.Invoker.PreOutput;
  650. if (invokerPreOutput != null)
  651. {
  652. var @continue = invokerPreOutput.Invoke(_context);
  653. if (!@continue) return;
  654. }
  655. var optionsPreOutput = _context.Options.PreOutput;
  656. if (optionsPreOutput != null)
  657. {
  658. var @continue = optionsPreOutput.Invoke(_context);
  659. if (!@continue) return;
  660. }
  661. // 设置头。
  662. var headers = PrepareHeaders(options, response, request);
  663. foreach (var header in headers) provider.SetHeader(header.Key, header.Value);
  664. // 自定义模型
  665. var model = response.Model as IApiModel;
  666. var result = response.Model as IActionResult;
  667. if (model != null)
  668. {
  669. try
  670. {
  671. model.Output(_context);
  672. }
  673. catch (Exception ex)
  674. {
  675. Logger.Internals.Exception(ex, model);
  676. }
  677. RuntimeUtility.Dispose(model);
  678. return;
  679. }
  680. else if (result != null)
  681. {
  682. try
  683. {
  684. result.ExecuteResult(_context);
  685. }
  686. catch (Exception ex)
  687. {
  688. Logger.Internals.Exception(ex, result);
  689. }
  690. RuntimeUtility.Dispose(result);
  691. return;
  692. }
  693. var text = ApiUtility.ToJson(response, options);
  694. var bytes = TextUtility.Bytes(text);
  695. provider.SetCache(0);
  696. provider.SetContentType("text/json; charset=utf-8");
  697. provider.SetContentLength(bytes.Length);
  698. var stream = provider.ResponseBody();
  699. if (stream != null && stream.CanWrite) stream.Write(bytes, 0, bytes.Length);
  700. provider.Sent();
  701. }
  702. #endregion
  703. }
  704. }