编写轻量ajax组件第三篇实现

网络编程 2025-04-04 09:14www.168986.cn编程入门

这篇文章详细地介绍了轻量级的ajax组件编写,特别是第三篇的实现部分。文章从基本的执行流程出发,逐步深入到具体的实现细节。

我们来回顾一下之前的内容。为了实现页面对象方法的执行,核心在于反射,这是一个从请求中获取参数并执行指定方法的过程。这与asp mvc框架的核心思想相似,即通过url来获取controller和action名称,然后激活相应的controller对象,并从请求中获取action参数执行action。在web form平台上,我们将方法写在.aspx.cs文件中,需要在页面对象还未生成的情况下执行指定的方法并返回结果。

接下来,我们看一下几个具体的ajax方法调用例子。这些方法展示了不同的参数类型、缓存设置和session状态管理。例如,Test1方法简单调用,Test2方法接收一个Test实例作为参数,Test3和Test4方法设置了输出缓存和服务端缓存,而Test5、Test6和Test7方法则展示了不同的session状态设置。

然后,文章引入了一个重要的概念——Ajax约定。主流浏览器在发送ajax异步请求时,通常会在请求头上带上一个X-Requested-With:XMLHttpRequest的标记。为了确保项目的独特性和不受其他组件的影响,我们加入了一个自定义的请求头。这个请求头包含了AjaxFlag和MethodName等关键信息,用于标识和处理ajax请求。

接下来,文章介绍了AjaxMethodAttribute标记属性。这个标记属性主要用于反射,定义了我们需要的一些功能,包括配置Session状态、支持异步Handler、支持Get缓存和支持服务端缓存等。这些功能使得我们的ajax组件更加灵活和强大。

Ajax方法中的属性奥秘:深入理解Session状态与输出内容类型

在Web开发中,我们经常使用Ajax方法来完成异步数据交互,而这些方法往往会包含许多属性以定制其表现。今天,我们将深入AjaxMethodAttribute这一属性及其相关的Session状态和输出内容类型。

让我们来看看AjaxMethodAttribute这个属性。它被设计为只能应用于方法上,并且不允许多个该属性同时存在于一个方法上。它包含一系列丰富的属性,允许开发者定制Ajax方法的各个方面。

其中,SessionState属性代表了Session的状态。它有三种可能值:None、ReadOnly和ReadWrite。这些值分别表示不支持Session、只支持读取Session数据和支持读写Session数据。通过设定这个属性,开发者可以决定Ajax方法是否需要或可以操作Session数据。

接下来是OutputCache和ServerCache属性。这两个属性用于控制客户端和服务端缓存时间,单位为秒。值得注意的是,OutputCache只对GET请求有效。通过设定这些属性,我们可以控制数据的缓存行为,提高应用的性能。

然后是ContentType属性。这个属性决定了Ajax方法的输出类型,默认值为text/plain。除此之外,它还可以是Html、XML、Javascript和JSON等。这使我们能够灵活地返回不同类型的数据,满足前端的需求。

IsAsync属性用于启用异步处理。通过设定这个属性,我们可以让Ajax方法以异步的方式执行,提高用户体验和应用的响应能力。

除了AjaxMethodAttribute,我们还定义了SessionState和ContentType两个枚举。它们分别代表了Session的状态和输出内容类型。这些枚举使代码更加清晰易懂,方便开发者选择和设定相应的值。

在实际应用中,各种处理程序和AjaxHandlerFactory扮演着重要的角色。它们负责处理不同的请求,并根据需求调用相应的Ajax方法。结合上面介绍的AjaxMethodAttribute属性,我们可以轻松地控制Ajax方法的各个方面,实现灵活的数据交互。

AjaxMethodAttribute及其相关属性为我们提供了丰富的定制选项,使我们能够根据需要调整Ajax方法的表现。通过深入理解这些属性的含义和用法,我们可以更好地利用它们,提高Web应用的质量和性能。在Web开发中,异步处理是一种重要的技术,它可以提高应用程序的性能和响应能力。为了实现异步处理,我们需要创建一个Handler,它必须实现IHttpAsyncHandler接口。这个接口继承自IHttpHandler接口,为我们提供了异步处理的基础架构。

当我们在开发过程中实现异步Handler时,关键的步骤在于定义ProcessRequest方法或者BeginProcessRequest方法。这些方法将承载我们主要的业务逻辑,它们是我们执行具体任务的地方。让我们深入了解这两个方法的作用和重要性。

ProcessRequest方法是一个核心方法,它是我们处理HTTP请求的主要场所。在这个方法中,我们可以编写代码来处理客户端发送的HTTP请求,例如读取请求数据、处理业务逻辑、与数据库交互等。由于这是同步处理方法,我们需要确保在此方法中的操作尽可能高效,以避免阻塞服务器线程,影响性能。

另一方面,BeginProcessRequest方法是异步处理的入口点。当调用此方法时,它标志着异步操作的开始。在这个方法中,我们可以启动异步任务来处理请求,并立即返回给客户端一个开始响应的消息。这样,客户端就不必等待服务器完成所有操作,从而提高了应用程序的响应能力。在BeginProcessRequest方法中,我们需要正确地管理异步任务,确保任务完成后能够正确地更新客户端的状态或发送响应数据。

为了实现高效的异步处理,我们还需要注意以下几点:

1. 使用线程安全的方式处理请求数据,确保并发访问时的数据安全性。

2. 优化数据库操作,避免阻塞操作,利用异步操作提高数据库访问效率。

3. 合理设计异步任务的结构和流程,确保任务能够正确地执行和完成。

实现异步Handler并正确使用IHttpAsyncHandler接口是提高Web应用程序性能和响应能力的关键。通过合理地设计和实现ProcessRequest方法和BeginProcessRequest方法,我们可以实现高效的异步处理,提高应用程序的性能和用户体验。在现代Web应用中,异步和同步处理扮演着重要的角色,它们关乎响应性能、用户体验以及资源利用。针对这两种处理模式,我们分别定义了一系列Handler,并对它们进行了精心的设计。

一、同步状态的Handler

不支持Session管理功能的同步Ajax处理器(SyncAjaxHandler),其核心是处理请求的逻辑,负责执行特定任务(如狼蚁网站的SEO优化详细介绍)。这个处理器接收一个页面对象(Page)、一个缓存方法信息对象(CacheMethodInfo)作为初始化参数。根据需求,我们创建了支持只读会话的SyncAjaxSessionReadOnlyHandler和支持读写会话的SyncAjaxSessionHandler两个子类。这些处理器均继承自SyncAjaxHandler类,通过实现不同的接口来满足不同的会话状态需求。

二、异步状态的Handler

对于需要更高响应性能的异步处理,我们有ASyncAjaxHandler作为核心处理器。它同样接收页面和缓存方法信息作为参数,并通过IHttpAsyncHandler接口实现异步处理逻辑。异步处理器通过IAsyncResult接口来处理异步操作的结果,包括开始请求处理(BeginProcessRequest)、结束请求处理(EndProcessRequest)。同样地,为了满足不同的会话状态需求,我们创建了ASyncAjaxSessionReadOnlyHandler和ASyncAjaxSessionHandler两个子类。

为了根据请求生成具体的Handler,我们实现了AjaxHandlerFactory工厂类,它实现了IHandlerFactory接口。这个工厂类需要在web.config文件中进行注册,以便根据请求类型动态生成对应的处理器。工厂模式的设计使得我们的系统更加灵活,可以根据不同的需求生成不同的处理器实例。

AjaxHandlerFactory中的GetHandler方法是我们处理请求的第一步重要关卡。我们的系统通过识别请求头的AjaxFlag:XHR来判断是否需要我们的特殊处理。如果识别到这一标志,我们就会着手创建一个专门的Handler。否则,我们会按照常规的页面处理方式来进行。鉴于我们的代码是写在.aspx.cs文件中的,我们的请求都是带有.aspx后缀的页面类型,这些页面通过PageHandlerFactory被创建出来。这个工厂实现了IHandlerFactory接口,意味着它是专门用来创建处理程序的。我们需要借助PageHandlerFactory来生成一个IHttpHandler。由于PageHandlerFactory的构造函数是protected internal类型的,我们无法直接实例化。为此,我们必须通过继承PageHandlerFactory创建一个自定义的CommonPageHandlerFactory来实现我们的需求。

在通过PageHandlerFactory获取到页面对象后,我们会结合方法名称进行反射操作,检索AjaxMethodAttribute标记属性。根据这些属性的不同配置,我们会生成特定的Handler来处理请求。具体的实现代码如下所示:

我们定义了一个内部类CommonPageHandlerFactory来继承PageHandlerFactory。然后,我们定义了一个AjaxHandlerFactory类来实现IHttpHandlerFactory接口。在GetHandler方法中,我们首先获取到HttpContext对象,然后从中获取HttpRequest对象。通过比较请求头的AjaxConfig.Key和AjaxConfig.Value来判断是否需要进行特殊处理。如果需要进行特殊处理,我们会检查函数标记,也就是请求头中的AjaxConfig.MethodName。如果未指定方法名称,我们会结束当前请求并返回null。如果指定了方法名称,我们会尝试创建一个CommonPageHandlerFactory实例,并通过它获取一个IHttpHandler对象。然后我们将尝试将这个Handler转换为Page类型。如果转换失败,说明处理程序类型必须是aspx页面,我们就会结束当前请求并返回null。如果一切顺利,我们就会根据页面对象、方法名称和上下文信息来创建并返回一个Handler对象来处理请求。如果在过程中发生任何异常,我们会记录错误信息并结束当前请求。

在这个数字时代,我们每天都在与无数的网站进行互动。你是否知道,在这背后隐藏着一种叫做“缓存机制”的技术,它与自定义处理程序共同协作,让我们的网页体验更加流畅。今天,让我们一起揭开这个神秘面纱,它们如何共同创造出无与伦比的网页体验。

让我们了解一下什么是缓存机制。简单来说,缓存就像是一个临时存储数据的空间,网站可以利用它存储访问过的页面或数据片段。当我们再次访问相同的页面或数据时,网站可以直接从缓存中读取数据,而不是重新生成页面或查询数据库。这就大大提高了网站的响应速度,让我们在浏览网页时感受到更加流畅的体验。

而在这个故事中,还有一个重要的角色——自定义处理程序。它就像是网站的幕后英雄,负责处理各种复杂的任务。当我们在网页上发起一个请求时,自定义处理程序就会根据我们的需求,执行相应的操作。例如,当我们在网页上点击一个按钮时,处理程序就会调用对应的方法,并返回结果。

那么,缓存机制和自定义处理程序是如何融合的呢?想象一下,当我们在网站上发起一个请求时,处理程序首先会检查缓存中是否有我们需要的数据。如果有,就直接返回缓存中的数据;如果没有,才会执行相应的操作,并将结果存储在缓存中。这样,下次我们再次发起相同的请求时,处理程序就可以直接返回缓存中的数据,大大提高了网站的响应速度。这就是缓存机制和自定义处理程序之间的奇妙融合。

在这个故事中,还有一个值得一提的技术——委托。委托是一种允许我们传递方法的特殊类型。在缓存机制中,我们可以将方法的委托进行缓存,而不是直接缓存方法的信息。这样,当需要执行方法时,我们就可以直接通过委托来执行方法,而不需要通过反射或其他方式去获取方法的信息。这不仅提高了效率,还使得代码更加简洁和易于维护。

缓存机制与自定义处理程序的融合是一种高效的网页技术。它们共同协作,让我们的网页体验更加流畅和快速。而委托技术的引入,更是为这种融合提供了强大的支持。希望这篇文章能够帮助你更好地理解这个技术背后的原理和思想。关于CacheMethodInfo的定义

在一个特定的技术框架内,CacheMethodInfo是一个用于描述缓存方法信息的密封类。此类具有以下核心属性:

一、方法名称(MethodName)

这个属性标识了一个特定的方法,其值作为该方法的唯一标识。每一个CacheMethodInfo实例都关联着一个特定的方法名称。

二、方法委托(Func)

这是一个委托属性,指向执行特定操作的方法。这个委托接受一个对象、一个对象数组作为参数,并返回一个对象。也就是说,这个委托代表了可以被缓存的方法的主要功能。

三、方法参数(Parameters)

此属性包含了方法的参数信息。这些信息对于理解方法的执行逻辑和调用方式至关重要。

四、Ajax标记属性(AjaxMethodAttribute)

这个属性描述了与Ajax相关的特定信息。Ajax技术是现代网页应用中常见的技术手段,这个属性存储了与Ajax请求关联的额外信息。

关于核心方法:Eexcutor.GetDelegateInfo获取方法相关信息

在编程的世界里,获取页面标记方法信息是一项至关重要的任务。想象一下,你正在处理一个复杂的网页应用,而这个应用由许多不同的页面组成,每个页面都有许多不同的方法。为了有效地管理和调用这些方法,我们需要一种机制来获取页面的方法信息,并将其转化为可以委托的形式。在这个场景中,我们介绍了一个名为“GetDelegateInfo”的方法。

GetDelegateInfo方法的主要任务是获取页面的特定方法的委托信息。它接受两个参数:一个页面对象和一个方法名称。这个方法首先检查页面对象是否为空,如果为空则抛出异常。接下来,它获取页面的类型,并从ajaxDelegateTable中获取与该类型关联的委托信息字典。如果字典不存在,它会创建一个新的字典并遍历页面的所有方法,找到带有AjaxMethodAttribute标记的方法,并将它们的信息添加到字典中。这些信息包括方法的名称、参数以及委托。如果字典已经存在,它会直接从中查找指定名称的方法信息并返回。

获取方法的委托是通过ReflectionUtil类实现的。这个类主要用于优化反射操作,它可以利用Expression将MethodInfo编译成特定的委托形式。例如,它可以为Type编译一个Func委托,用于创建实例对象。在这个例子中,ReflectionUtil.GetMethodDelegate方法被用来根据MethodInfo获取方法的委托。这个委托可以被用来在运行时动态调用方法,提高了代码的灵活性和效率。

GetDelegateInfo方法为我们提供了一个强大的工具,使我们能够方便地获取页面的方法信息并将其转化为可以委托的形式。这使得我们能够更加灵活地管理和调用页面的方法,提高了代码的可维护性和效率。无论是开发复杂的网页应用还是进行性能优化,这个方法都是一个非常有用的工具。优化反射与表达式树的应用

表达式树(Expression Tree)是一种将代码逻辑以表达式形式存储在树状结构中的技术,它允许我们在运行时动态、编辑和执行代码。在ORM框架中,表达式树被广泛使用,例如Users.Where(u => u.Age > 18)语句,它允许我们以面向对象的方式读写数据库,而无需编写复杂的SQL语句。本文将介绍如何使用表达式树并如何利用它生成委托。

我们需要理解表达式树的构建过程。Expression是一个抽象类,所有表达式类型都派生自它,并由它来创建。我们可以将其视为一个工厂类。为了更直观地解释这个概念,让我们看一个简单的例子:表达式 1 + 2 3。在表达式树中,这个表达式将被表示为根节点为加法操作的树,其中包含了两个子节点,分别代表两个子表达式 2 和 3 的乘法结果。通过这种方式,复杂的表达式可以被结构化地表示和处理。

接下来,我们如何利用表达式树生成委托呢?我们需要定义参数和常量。例如,在表达式 a b + c 中,a、b和c都是参数或常量。我们可以通过Expression.Parameter和Expression.Constant方法来创建它们。然后,我们可以使用Expression.Multiply和Expression.Add等方法创建乘法运算和加法运算的节点。我们将这些节点组合成一个完整的表达式树,并将其转换为一个委托表达式。这个委托表达式可以被编译成可执行代码,从而生成一个可以直接调用的函数。这样,我们就可以通过表达式树实现从抽象语法到可执行的代码的转换。

通过这种方式,我们可以将复杂的代码逻辑通过表达式树和委托的形式进行封装和重用。这不仅提高了代码的可读性和可维护性,而且允许我们在运行时动态地生成和执行代码,从而实现更大的灵活性和可扩展性。这对于动态生成SQL语句、构建动态查询等场景特别有用。通过深入理解表达式树和委托的工作原理,我们可以更好地利用这些技术来优化我们的代码和程序。狼蚁网站的SEO优化策略介绍:我们实际实施的方法及其背后的代码实现

在数字化时代,搜索引擎优化(SEO)对于网站的可见性和流量至关重要。狼蚁网站深知此道,并运用一系列策略来提升其在搜索引擎中的排名。接下来,我们将深入其背后的方法实现,并展示关键代码片段。

为了实现高效的SEO优化,狼蚁网站团队首先开发了一个重要的工具函数——GetMethodDelegate。这个函数接受一个MethodInfo对象作为参数,用于生成一个Func类型的委托。这个委托将被用于缓存方法信息,并在运行时动态调用对应的方法。接下来让我们深入了解代码细节。

函数检查输入的MethodInfo对象是否为空。如果为空,则抛出一个异常。然后,它定义了两个参数表达式:一个表示委托的第一个参数(实例),另一个表示委托的第二个参数(参数数组)。

接下来,函数获取方法的参数信息数组,并根据这些信息构建参数表达式集合。对于每个参数,它从参数数组中提取第i个元素,将其转换为与参数类型一致的类型,并将其添加到参数集合中。

然后,函数检查方法是否为静态方法。如果不是静态方法,它将构建实例表达式并将其转换为方法所属的类型。接下来,它创建表示调用方法的表达式。这个表达式将使用实例表达式、方法信息和参数集合来调用目标方法。

函数根据方法调用的返回类型编译Lambda表达式并返回相应的委托。如果方法没有返回类型(即返回类型为void),则返回一个Action类型的委托。否则,它将返回一个Func类型的委托,该委托将方法调用的结果转换为object类型。

这个GetMethodDelegate函数是狼蚁网站SEO优化中的关键部分。通过动态生成委托,它可以实现方法的动态调用和缓存,从而提高网站的响应速度和性能。通过优化代码结构和提高代码可读性,狼蚁网站确保了搜索引擎能够更容易地理解和索引其内容,从而提高了网站的搜索引擎排名。

狼蚁网站通过实施一系列有效的SEO优化策略和方法,结合先进的代码实现,成功提升了其在搜索引擎中的可见性和流量。这种方法不仅提高了用户体验,还为企业带来了更多的商业机会和收入。对于想要测试反射性能的朋友们,这里提供了一个绝佳的机会去尝试并对比几种不同执行方式的效率差异。让我们逐一看看这些方式:直接执行方法、Emit、缓存加委托以及Delegate.DynamicInvoke。

接下来,我们来一下“Executor.Execute 执行委托”这一概念。

在执行委托之前,我们首先需要从请求中获取参数,并将这些参数映射到相应的方法上。这些参数可以是简单的类型,如字符串Test(int i,int j);也可以是一个复杂的对象,如字符串Test(User user)。如果参数是两个用户对象,如字符串Test(User user1, User user2),在提交参数时,我们只需加上user1或user2的前缀即可,例如user1.Name,user2.Name。

虽然这里并未支持像MVC那样的更多匹配方式,如嵌套类型等,但你可以根据自己的需求去扩展实现。当参数是一个对象时,我们可能需要为其字段或属性进行赋值。

为了表示字段或属性的父类,我们定义一个抽象类——DataMember。这个类具有以下几个关键特性:

1. Name:表示成员的名称。

2. MemberType:表示成员的类型。

3. SetValue(object instance, object value):为对象的实例设置值。

4. GetValue(object instance):从对象的实例中获取值。

在此基础上,我们可以进一步定义属性类型PropertyMember和字段类型FieldMember,它们分别继承了DataMember类。

PropertyMember与FieldMember的定义

在编程的世界里,我们经常会遇到对属性的操作和对字段的访问。为此,我们定义了两个类——`PropertyMember`和`FieldMember`,它们继承自`DataMember`。它们分别代表一个属性或一个字段,拥有对实例进行操作的能力。当创建这两个类的实例时,我们必须提供一个属性或字段的信息。如果提供的属性或字段为空,程序会抛出异常。这两个类的主要职责就是设置和获取实例的值。除此之外,它们还提供了获取名称和类型的方法。

DataMemberManager的管理

为了更好地管理这些属性与字段,我们创建了一个名为`DataMemberManager`的静态类。这个类有一个方法,能够接收一个类型作为参数,然后返回该类型的所有公共实例属性与字段的集合。我们遍历了类型的所有属性和字段,并创建对应的`PropertyMember`和`FieldMember`实例添加到集合中。这样我们就可以轻松地获取和操作类型的所有属性与字段了。

Handler中的Execute方法

在我们的程序中,有一个核心的函数叫做`Execute`。这个函数是执行Handler的方法,它接收一个页面对象、一个请求上下文和一个缓存方法信息作为参数。它会检查传入的参数是否有效。如果参数有效并且缓存方法信息不为空,它会从请求中获取参数,并调用相应的方法执行。如果服务器缓存设置开启,它还会将数据缓存起来。如果找不到合适的方法,它会结束当前请求并返回一个错误信息。整个执行过程被包裹在一个try-catch块中,以处理可能出现的异常。这就是我们的核心函数在处理请求时的基本工作流程。

这样的设计使得我们的程序更加模块化、灵活和易于维护。无论是获取属性还是字段,无论是管理数据成员还是执行处理程序,我们的代码都清晰明了,易于理解。这就是编程的魅力所在,通过精心的设计和编码,我们可以创造出强大的工具来帮助我们实现各种复杂的任务。在处理方法调用时,我们首先要确保拥有正确的信息以执行它。我们已经成功获取了CacheMethodInfo,这是执行方法的关键所在。接下来,我们需要从请求中获取参数,以便正确地调用该方法。这个过程涉及到一种名为GetParameterFromRequest的功能,它的任务是生成一个对象数组,这些对象代表了我们需要传递给方法的参数。这个过程既需要处理简单的数据类型,也需要处理复杂的实例对象。

对于简单的数据类型,转换过程相对直接。这些类型通常可以直接从请求中获取,然后进行必要的类型转换,以确保它们符合方法的参数要求。这一过程需要精确的处理,以确保数据的准确性和类型的匹配性。一旦完成,这些参数就可以被添加到参数数组中,为执行方法做好准备。

对于复杂的实例对象,处理过程就更为复杂了。在这种情况下,我们需要首先创建一个新的实例对象。然后,根据请求中的数据,我们需要为这些新创建的实例对象的字段或属性赋值。这个过程涉及到对数据的深入理解,以及对对象结构的确切知识。我们需要确保为每个字段或属性赋予正确的值,这样才能保证实例对象的完整性和功能性。一旦所有的字段或属性都被正确赋值,这些实例对象就可以被添加到参数数组中,以完成方法的调用。

原文代码段:

```csharp

// 从请求获取参参数

private static object[] GetParametersFromRequest(HttpRequest request, ParameterInfo[] parameters)

{

// 省略部分代码...

}

```

```csharp

/ 从HTTP请求中提取参数数组 /

private static object[] ExtractParametersFromHttpRequest(HttpRequest request, ParameterInfo[] parameters)

{

if (parameters == null || parameters.Length == 0)

{

return null; // 若无参数则直接返回null

}

object[] parameterValues = new object[parameters.Length]; // 创建参数数组以存储提取的值

Type parameterType; // 用于存储当前参数的类型的临时变量

object parameterValue; // 用于存储从请求中获取的参数值的临时变量

for (int i = 0; i < parameters.Length; i++) // 遍历所有参数信息以获取值并转换类型

{

parameterType = parameters[i].ParameterType; // 获取当前参数的类型信息

构造函数委托的奥秘

在编程世界中,有时我们需要获取特定类型的构造函数委托。这是一种强大的技术,允许我们在运行时动态创建对象实例。让我们深入一下如何实现这一功能。

当我们面对一个类型时,首先需要确保该类型具有一个无参的公共构造函数。这是获取构造函数委托的前提。我们可以通过反射来获取类型的构造函数信息。如果类型没有这样的构造函数,我们将无法创建其委托。

接下来,我们可以使用表达式树来创建构造函数的委托。表达式树是一个功能强大的工具,它允许我们以树形结构表示LINQ表达式,从而能够动态地生成代码。通过表达式树,我们可以创建一个表示新对象实例的表达式,并将其编译成委托。

关于缓存的处理,当我们在处理HTTP请求时,对于GET请求并且需要缓存的情况,我们需要对Response.Cache进行设置。这涉及到设置缓存的有效期、缓存策略等。如果缓存时间为负,则表示不缓存。对于前台脚本库的调用,我们只需按照约定的方式调用相应的标记方法即可。

我们的组件具有强大的扩展性,您可以根据自己的需求进行定制和扩展。我们也非常欢迎与您共同学习和交流,共同编程的奥秘和乐趣。在这个组件的帮助下,您可以轻松地获取构造函数委托并处理缓存问题。现在只需执行一句简单的命令“cambrian.render('body')”,即可启动您的应用程序之旅。让我们一起踏上这场编程的之旅吧!

上一篇:CefSharp v62修改方法(支持.net4.0) 下一篇:没有了

Copyright © 2016-2025 www.168986.cn 狼蚁网络 版权所有 Power by