<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      接口 IResultFilter、IAsyncResultFilter 的簡介和用法示例(.net)

      〇、IResultFilter、IAsyncResultFilter 接口簡介

      IResultFilter 是 ASP.NET Core MVC 管道中一個非常重要的過濾器接口,它主要是在操作結果(IActionResult)被執(zhí)行之前和之后,來執(zhí)行自定義邏輯

      這里的“操作結果”指的是控制器動作方法返回的 IActionResult 實例,例如 ViewResult、JsonResult、RedirectResult、ContentResult 等。

      接口定義:

      #region 程序集 Microsoft.AspNetCore.Mvc.Abstractions, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
      // C:\Program Files\dotnet\packs\Microsoft.AspNetCore.App.Ref\3.1.10\ref\netcoreapp3.1\Microsoft.AspNetCore.Mvc.Abstractions.dll
      #endregion
      
      namespace Microsoft.AspNetCore.Mvc.Filters
      {
          // 摘要:一個過濾器,用于在操作完成后對結果的加工
          public interface IResultFilter : IFilterMetadata
          {
              // 摘要:在操作結果【執(zhí)行前】調用
              void OnResultExecuting(ResultExecutingContext context);
              // 摘要:在操作結果【執(zhí)行后】調用
              void OnResultExecuted(ResultExecutedContext context);
          }
          // 異步版本【推薦使用】
          public interface IAsyncResultFilter : IFilterMetadata
          {
              Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next);
          }
      }

      由于 IAsyncResultFilter 提供了更好的異步支持(避免了 async void 的坑),并且可以更靈活地控制執(zhí)行流程(通過調用 next()),通常建議實現 IAsyncResultFilter 而不是 IResultFilter。

      IResultFilter 可以用于:

      修改操作結果:在結果執(zhí)行前,可以檢查、修改甚至替換即將執(zhí)行的 IActionResult。
      在結果執(zhí)行后執(zhí)行邏輯:在結果(如視圖渲染完成、JSON 序列化完成、重定向發(fā)生后)執(zhí)行完畢后,執(zhí)行一些清理、日志記錄或審計操作。
      短路結果執(zhí)行:在 OnResultExecuting 中,通過設置 ResultExecutingContext.Result 并調用 ResultExecutingContext.Cancel = true,可以完全跳過原始結果的執(zhí)行,直接返回一個新的結果

      重要區(qū)別:不要將 IResultFilter IActionFilter 混淆。

      • IActionFilter 作用于控制器動作方法本身的執(zhí)行前后(OnActionExecuting, OnActionExecuted)。
      • IResultFilter 作用于動作方法返回的結果(IActionResult)的執(zhí)行前后。

      一、方法 void OnResultExecuting(ResultExecutingContext context):操作結果執(zhí)行前

      1.1 簡介

      調用時機:在框架準備執(zhí)行 IActionResult(例如,開始渲染視圖或序列化 JSON)之前立即調用。

      // 執(zhí)行大概順序:
      AuthorizationFilter
              ↓
      ResourceFilter
              ↓
      ActionFilter (OnActionExecuting)
              ↓
      Controller Action Method Executes
              ↓
      ActionFilter (OnActionExecuted)
              ↓
      IResultFilter (OnResultExecuting) // ← 【在這里】
              ↓
      IActionResult Executes (e.g., View renders, JSON serializes)
              ↓
      IResultFilter (OnResultExecuted)
              ↓
      ExceptionFilter
              ↓
      ResourceFilter

      此時 Action 已經執(zhí)行完畢,IActionResult 對象已經創(chuàng)建,但結果(如視圖、JSON 響應)尚未執(zhí)行或寫入響應流。此時可以修改或替換即將執(zhí)行的 IActionResult。

      主要用途:

      • 檢查/修改 IActionResult:通過 context.Result 獲取或設置即將執(zhí)行的結果。可以修改它的屬性,或者完全替換它。
      • 短路執(zhí)行:這是 IResultFilter 最強大的功能之一。可以通過創(chuàng)建一個新的 IActionResult(如 ContentResult, JsonResult, RedirectResult 等),將其賦值給 context.Result,然后設置 context.Cancel = true,這將阻止原始結果的執(zhí)行,框架會立即執(zhí)行你提供的新結果。
      • 執(zhí)行前置邏輯:如記錄日志、驗證某些條件、向 HttpContext.Response 添加響應頭等。

      ResultExecutingContext 參數:

      • context.Result: 表示即將被執(zhí)行的 IActionResult。
        • 讀取它(例如,檢查返回的是 JsonResult 還是 ViewResult)。
        • 修改它(例如,替換為另一個 IActionResult,如將 JsonResult 改為 ContentResult)。
      • context.Cancel:通過設置 context.Result 為一個新結果并調用 context.Cancel = true,可以阻止原始結果的執(zhí)行,并立即返回你設置的結果。
      • context.Controller:獲取當前控制器實例。
      • context.HttpContext:獲取當前 HTTP 上下文,可用于訪問請求、響應、會話等。
      • context.Canceled:指示執(zhí)行是否已被取消(通常由其他篩選器設置)。
      • context.ActionDescriptor:提供關于當前執(zhí)行的動作的信息。
      • context.ModelState:提供關于模型驗證狀態(tài)的信息。

      1.2 簡單的示例:添加自定義響應頭

      public class AddHeaderResultFilter : IResultFilter
      {
          public void OnResultExecuting(ResultExecutingContext context)
          {
              // 在結果執(zhí)行前添加一個自定義響應頭
              context.HttpContext.Response.Headers.Add("X-Custom-Header", "MyValue");        
              // 繼續(xù)執(zhí)行原始結果
          }
      
          public void OnResultExecuted(ResultExecutedContext context)
          {
              // 結果執(zhí)行后可以記錄日志
              Console.WriteLine($"Result '{context.Result}' executed for {context.HttpContext.Request.Path}");
          }
      }

      1.3 示例:短路結果執(zhí)行

      public class MaintenanceModeResultFilter : IResultFilter
      {
          private readonly bool _isInMaintenanceMode;
      
          public MaintenanceModeResultFilter(bool isInMaintenanceMode)
          {
              _isInMaintenanceMode = isInMaintenanceMode;
          }
      
          public void OnResultExecuting(ResultExecutingContext context)
          {
              if (_isInMaintenanceMode)
              {
                  // 創(chuàng)建一個維護模式的響應結果
                  var maintenanceResult = new ContentResult
                  {
                      Content = "<h1>網站正在維護中,請稍后再試。</h1>",
                      ContentType = "text/html"
                  };
      
                  // 將新結果賦值給 context
                  context.Result = maintenanceResult;
                  // 取消原始結果的執(zhí)行
                  context.Cancel = true; 
              }
              // 如果不在維護模式,不設置 Cancel,原始結果將繼續(xù)執(zhí)行
          }
      
          public void OnResultExecuted(ResultExecutedContext context)
          {
              // 如果被短路,這里仍然會執(zhí)行
              if (context.Canceled)
              {
                  Console.WriteLine("Result execution was canceled (Maintenance Mode).");
              }
          }
      }

      1.4 示例:記錄結果執(zhí)行時間

      public class TimingResultFilter : IResultFilter
      {
          private const string StopwatchKey = "ResultExecutionStopwatch";
      
          public void OnResultExecuting(ResultExecutingContext context)
          {
              // 開始計時
              var stopwatch = Stopwatch.StartNew();
              context.HttpContext.Items[StopwatchKey] = stopwatch;
          }
      
          public void OnResultExecuted(ResultExecutedContext context)
          {
              // 停止計時并記錄
              if (context.HttpContext.Items[StopwatchKey] is Stopwatch stopwatch)
              {
                  stopwatch.Stop();
                  Console.WriteLine($"Result '{context.Result.GetType().Name}' executed in {stopwatch.ElapsedMilliseconds}ms.");
              }
          }
      }

      二、方法 void OnResultExecuted(ResultExecutedContext context):操作結果執(zhí)行后

      2.1 簡介

      調用時機:在 IActionResult 已經執(zhí)行完畢之后調用。如果 OnResultExecuting 中發(fā)生了異常,或者執(zhí)行被短路(context.Cancel = true),這個方法仍然會執(zhí)行。

      執(zhí)行順序,詳見本文章節(jié):1.1。

      主要用途:

      • 執(zhí)行后置邏輯:如記錄日志、審計、清理資源。
      • 檢查執(zhí)行結果:通過 context.Result 可以查看最終執(zhí)行的是哪個結果(可能是原始結果,也可能是 OnResultExecuting 中設置的新結果)。
      • 檢查異常:通過 context.Exception 可以檢查在結果執(zhí)行過程中是否發(fā)生了未處理的異常(如果 context.Exception 不為 null)。注意,如果異常被處理了(例如在過濾器中捕獲并設置了結果),Exception 可能為 null。

      ResultExecutedContext 參數:

      context.Result:獲取最終執(zhí)行的 IActionResult(在 OnResultExecuting 中可能已被修改)。

      context.Exception:獲取在結果執(zhí)行過程中發(fā)生的未處理異常。如果為 null,表示沒有異常。

      context.HttpContext, context.ActionDescriptor, context.ModelState:與 ResultExecutingContext 中的同名屬性作用相同。

      context.Canceled:如果執(zhí)行在 OnResultExecuting 中被取消(context.Cancel = true),則此屬性為 true。

      2.2 示例:記錄日志

      using Microsoft.AspNetCore.Mvc.Filters;
      using Microsoft.Extensions.Logging;
      using System.Diagnostics;
      
      // 實現 IResultFilter 接口
      public class SimpleLoggingResultFilter : IResultFilter
      {
          private readonly ILogger<SimpleLoggingResultFilter> _logger;
          private readonly Stopwatch _stopwatch; // 用于計算執(zhí)行時間
          // 通過依賴注入獲取 ILogger
          public SimpleLoggingResultFilter(ILogger<SimpleLoggingResultFilter> logger)
          {
              _logger = logger;
              _stopwatch = new Stopwatch();
          }
          // IResultFilter.OnResultExecuting: 在 Result 執(zhí)行前調用
          // 這里我們用它來啟動計時器
          public void OnResultExecuting(ResultExecutingContext context)
          {
              _stopwatch.Restart(); // 重置并啟動計時器
              _logger.LogDebug($"準備執(zhí)行結果: {context.HttpContext.Request.Path}");
          }
          // IResultFilter.OnResultExecuted: 在 Result 執(zhí)行后調用
          // 這是記錄最終日志的主要方法
          public void OnResultExecuted(ResultExecutedContext context)
          {
              _stopwatch.Stop(); // 停止計時器
              var httpContext = context.HttpContext;
              var request = httpContext.Request;
              var response = httpContext.Response;
              // 獲取狀態(tài)碼
              int statusCode = response.StatusCode;
              // 構建日志消息
              var logMessage = $"請求完成 - " +
                              $"路徑: {request.Path}, " +
                              $"方法: {request.Method}, " +
                              $"狀態(tài)碼: {statusCode}, " +
                              $"耗時: {_stopwatch.ElapsedMilliseconds}ms";
      
              // 根據狀態(tài)碼選擇日志級別
              if (statusCode >= 500)
              {
                  _logger.LogError(logMessage);
              }
              else if (statusCode >= 400)
              {
                  _logger.LogWarning(logMessage);
              }
              else
              {
                  _logger.LogInformation(logMessage);
              }
              // 如果 Result 執(zhí)行過程中發(fā)生了未處理的異常
              if (context.Exception != null)
              {
                  _logger.LogError(context.Exception, "Result 執(zhí)行中發(fā)生未處理異常");
              }
              // 注意: OnResultExecuted 之后,響應通常已經發(fā)送給客戶端
              // 在這里修改 context.Result 或設置跳過 (context.Canceled = true) 通常無效或可能導致錯誤
              // 因為響應流可能已經關閉。
          }
      }

      三、方法 Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next):異步方式【推薦使用】

      3.1 簡介

      OnResultExecutionAsync 是 IAsyncResultFilter 接口的核心方法,它可以取代舊的同步 IResultFilter 接口,提供了更靈活、更強大的異步處理能力

      ResultExecutingContext context:這個 context 對象封裝了 IActionResult 即將執(zhí)行時的環(huán)境信息。

      幾個常用參數:

      context.Result: 這是即將被執(zhí)行的 IActionResult 實例(如 ViewResult, JsonResult, RedirectResult 等)。你可以讀取、修改這個屬性,甚至替換它。
      context.HttpContext: 提供對當前 HTTP 請求和響應的完全訪問。這是你操作響應頭、讀取請求信息、訪問會話等的主要途徑。
      context.Controller: 指向執(zhí)行該結果的控制器實例。
      context.Canceled: 一個 bool 屬性。如果設置為 true,它會短路 (short-circuit) 后續(xù)的篩選器管道和 IActionResult 的執(zhí)行。注意:僅僅設置 context.Canceled = true 并不會自動產生響應;你通常需要同時設置 context.Result 來提供一個替代的響應。

      ResultExecutionDelegate next:這是一個委托(delegate),本質上是一個 Func<Task<ResultExecutedContext>>。

      調用 await next() 會繼續(xù)執(zhí)行篩選器管道,最終導致 IActionResult 被實際執(zhí)行(例如,視圖被渲染,JSON 被序列化)。

      await next() 的返回值是一個 ResultExecutedContext 對象,它包含了 IActionResult 執(zhí)行完成后的狀態(tài)信息。

      • 執(zhí)行流程與 next() 的關鍵作用

      為什么說 OnResultExecutionAsync 的執(zhí)行流程是環(huán)繞式 (around) 的?

      • 前處理 (Before):你的代碼首先執(zhí)行 await next() 之前的邏輯。這對應于舊的 OnResultExecuting 階段。
      • 調用 next():await next() 調用是核心。
        • 觸發(fā)剩余的 IResultFilter/IAsyncResultFilter 的 OnResultExecutionAsync 方法(如果存在)。
        • 最終執(zhí)行 IActionResult.ExecuteResultAsync (或同步版本)。
        • 返回一個 ResultExecutedContext。
      • 后處理 (After):await next() 完成后,你的代碼繼續(xù)執(zhí)行 await next() 之后的邏輯。這對應于舊的 OnResultExecuted 階段。此時,IActionResult 已經執(zhí)行完畢。

      next() 的強大之處在于:它可以精確控制代碼在結果執(zhí)行前和后的運行,而且開發(fā)者還可以選擇不調用 next(),從而完全阻止原始 IActionResult 的執(zhí)行。

      • ResultExecutedContext(來自 await next())

      當 await next() 完成后,可以得到一個 ResultExecutedContext。它的關鍵屬性包括:

      context.Result: 執(zhí)行后的 IActionResult(可能在管道中被修改過)。
      context.Exception: 如果在 IActionResult 執(zhí)行過程中或之后的篩選器中拋出了未處理的異常,這里會包含該異常。
      context.ExceptionHandled: 一個 bool,表示異常是否已被某個篩選器標記為已處理。如果 context.Exception != null && !context.ExceptionHandled,說明有一個未處理的異常。
      context.Canceled: 表示執(zhí)行是否被取消(通常由前面的篩選器設置)。
      context.HttpContext: 執(zhí)行完成后的上下文。

      3.2 示例一:添加自定義響應頭

      如下,是最常見的用法之一。在結果執(zhí)行前設置響應頭,確保所有通過 MVC 返回的響應都包含這些安全或元數據頭。

      using Microsoft.AspNetCore.Mvc.Filters;
      using System.Threading.Tasks;
      
      public class SecurityHeadersFilter : IAsyncResultFilter
      {
          public async Task OnResultExecutionAsync(
              ResultExecutingContext context,
              ResultExecutionDelegate next)
          {
              var response = context.HttpContext.Response;
              // 添加安全相關的響應頭
              response.Headers.Add("X-Content-Type-Options", "nosniff");
              response.Headers.Add("X-Frame-Options", "DENY");
              response.Headers.Add("X-XSS-Protection", "1; mode=block");
              // 注意:Content-Security-Policy 非常復雜,這里只是簡單示例
              response.Headers.Add("Content-Security-Policy", "default-src 'self'");
              // 添加自定義頭
              response.Headers.Add("X-Generated-By", "My ASP.NET Core App");
              // 繼續(xù)執(zhí)行后續(xù)的篩選器和 IActionResult
              await next();
          }
      }

      3.3 示例二:響應結果包裝(API 版本化或統(tǒng)一格式)

      如下,過濾器將所有 JsonResult 的響應體包裝在一個包含元數據(如成功標志、時間戳)的通用結構中。這對于構建 RESTful API 非常有用,可以提供一致的響應格式。

      using Microsoft.AspNetCore.Mvc;
      using Microsoft.AspNetCore.Mvc.Filters;
      using System.Threading.Tasks;
      
      public class ApiResponseWrapperFilter : IAsyncResultFilter
      {
          public async Task OnResultExecutionAsync(
              ResultExecutingContext context,
              ResultExecutionDelegate next)
          {
              // 1. 檢查當前結果是否是 JsonResult (我們只包裝 JSON 響應)
              if (context.Result is not JsonResult)
              {
                  // 不是 JSON,直接繼續(xù)執(zhí)行
                  await next();
                  return;
              }
              // 2. 準備包裝對象
              var originalResult = context.Result as JsonResult;
              var wrappedResponse = new
              {
                  Success = true, // 假設操作成功
                  Timestamp = DateTime.UtcNow,
                  Data = originalResult.Value, // 將原始數據放入包裝對象的 Data 屬性
                  // Version = "1.0" // 可以加入 API 版本信息
              };
              // 3. 替換 context.Result 為新的 JsonResult
              context.Result = new JsonResult(wrappedResponse)
              {
                  // 保持原始 JsonResult 的序列化設置 (如 JsonSerializerOptions)
                  SerializerSettings = (originalResult as JsonResult)?.SerializerSettings
              };
              // 4. 繼續(xù)執(zhí)行。現在執(zhí)行的是我們包裝后的 JsonResult
              await next();
          }
      }
      
      // 使用示例控制器
      [ApiController]
      [Route("api/[controller]")]
      public class TestController : ControllerBase
      {
          [HttpGet]
          public IActionResult GetData()
          {
              // 返回的匿名對象會被 ApiResponseWrapperFilter 包裝
              return Ok(new { Name = "John", Age = 30 });
              // 最終響應體: { "Success": true, "Timestamp": "...", "Data": { "Name": "John", "Age": 30 } }
          }
      }

      3.4 示例三:基于條件的短路 (Short-circuiting) - 簡單緩存

      如下,過濾器演示了強大的短路能力。它在 IActionResult 執(zhí)行前檢查緩存,如果命中,則直接用緩存的結果替換 context.Result 并設置 context.Cancel = true,從而跳過昂貴的 IActionResult 執(zhí)行過程(如數據庫查詢、視圖渲染)。如果未命中,則執(zhí)行 next(),并在執(zhí)行成功后將結果存入緩存。

      using Microsoft.AspNetCore.Mvc.Filters;
      using Microsoft.Extensions.Caching.Memory;
      using System.Threading.Tasks;
      
      public class SimpleCacheFilter : IAsyncResultFilter
      {
          private readonly IMemoryCache _cache;
      
          public SimpleCacheFilter(IMemoryCache cache)
          {
              _cache = cache;
          }
      
          public async Task OnResultExecutionAsync(
              ResultExecutingContext context,
              ResultExecutionDelegate next)
          {
              // 1. 為當前請求生成一個緩存鍵 (簡化示例,實際中需要更健壯的鍵)
              var cacheKey = $"Result_{context.HttpContext.Request.Path}";
              // 2. 嘗試從緩存中獲取結果
              if (_cache.TryGetValue(cacheKey, out object cachedResult))
              {
                  // 3. 緩存命中!短路執(zhí)行
                  // 將緩存的結果設置為 context.Result
                  context.Result = cachedResult as IActionResult;
                  // 標記為已取消,阻止 next() 執(zhí)行
                  context.Cancel = true;
                  // 記錄命中日志
                  Console.WriteLine($"Cache HIT for {cacheKey}");
                  return; // 直接返回,不執(zhí)行 next()
              }
              // 4. 緩存未命中,繼續(xù)執(zhí)行原始的 IActionResult
              // 注意:我們調用 next(),它會返回 ResultExecutedContext
              var executedContext = await next();
              // 5. 檢查執(zhí)行是否成功且沒有異常/取消
              if (!executedContext.Canceled && executedContext.Exception == null)
              {
                  // 6. 將執(zhí)行后的結果(注意是 context.Result,不是 executedContext.Result)存入緩存
                  // (假設我們信任 context.Result 在執(zhí)行后是有效的)
                  _cache.Set(cacheKey, context.Result, TimeSpan.FromMinutes(5));
                  Console.WriteLine($"Cache SET for {cacheKey}");
              }
              // 如果執(zhí)行被取消或有異常,通常不緩存
          }
      }

      3.5 示例四:性能監(jiān)控(測量 IActionResult 執(zhí)行時間)

      如下,過濾器精確測量了 IActionResult 本身(不包括動作方法執(zhí)行時間)的執(zhí)行耗時。這對于識別性能瓶頸非常有用。try/finally 確保即使發(fā)生異常也能記錄時間。

      using Microsoft.AspNetCore.Mvc.Filters;
      using System.Diagnostics;
      using System.Threading.Tasks;
      
      public class PerformanceMonitorFilter : IAsyncResultFilter
      {
          public async Task OnResultExecutionAsync(
              ResultExecutingContext context,
              ResultExecutionDelegate next)
          {
              var stopwatch = Stopwatch.StartNew();
              try
              {
                  // 執(zhí)行 IActionResult
                  await next();
              }
              finally
              {
                  stopwatch.Stop();
                  var elapsedMs = stopwatch.ElapsedMilliseconds;
                  // 獲取請求信息
                  var requestPath = context.HttpContext.Request.Path;
                  var httpMethod = context.HttpContext.Request.Method;
                  var statusCode = context.HttpContext.Response.StatusCode;
                  // 記錄性能日志 (這里用 Console 代替實際的日志框架)
                  Console.WriteLine($"[{httpMethod}] {requestPath} -> Status: {statusCode}, " +
                                  $"Result Execution Time: {elapsedMs}ms");
                  // 在實際應用中,這里可能會發(fā)送到 Application Insights, Prometheus, 或寫入日志文件
              }
          }
      }

      四、過濾器的注冊

      注冊可以在三個地方實現,如下:

      // 在 Program.cs 中注冊
      var builder = WebApplication.CreateBuilder(args);
      builder.Services.AddControllers(options =>
      {
          options.Filters.Add<ApiResponseWrapperFilter>();
          options.Filters.Add<AddHeaderFilter>();
      });
      
      // 在 Controller/Action 上使用特性
      [ServiceFilter(typeof(ApiResponseWrapperFilter))]
      public class HomeController : Controller
      {
          // ...
      }
      posted @ 2025-08-31 22:03  橙子家  閱讀(58)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 狠狠色丁香婷婷综合尤物| 国产乱子伦农村xxxx| 国产精品粉嫩嫩在线观看| 久久无码专区国产精品| 亚洲人成电影网站 久久影视 | 成av免费大片黄在线观看| 十四以下岁毛片带血a级| 久热久热久热久热久热久热| 无码人妻一区二区三区线| 少妇av一区二区三区无码| 泸州市| 亚洲国产精品一区二区久| 国产日韩一区二区四季| 日夜啪啪一区二区三区| 国产av丝袜熟女一二三| 国产AV巨作丝袜秘书| 九九热精品免费视频| 麻豆aⅴ精品无码一区二区| 亚洲第一狼人成人综合网| 亚洲中文字幕国产精品| 国产精品一区二区中文| 999国产精品999久久久久久| 免费人欧美成又黄又爽的视频| 国产免费性感美女被插视频| 亚洲欭美日韩颜射在线二| 国产精品人成在线观看免费| 在线日韩日本国产亚洲| 午夜福利精品国产二区| 天堂网亚洲综合在线| 午夜男女爽爽影院免费视频下载| 欧美黑吊大战白妞| 国产偷国产偷亚洲清高网站| 丰满的少妇一区二区三区| 性欧美vr高清极品| 国产肥臀视频一区二区三区| 亚洲精品香蕉一区二区| 欧美激情一区二区三区成人| 黄骅市| 中文字幕av无码一区二区蜜芽三区 | 黄色大全免费看国产精品| 成人无码午夜在线观看|