问题简介
在ASP.NET程序中我们经常遇到错误消息为"Request
Timed Out"的HttpException,浏览器中的出错信息如下图所示,
同时应用程序日志中也会出现一条警告消息如下
如何重现这种异常?
线程在处理逻辑的过程中是如何被打断而抛出超时异常?
如何调试这种异常?
这篇文章我们从CLR源代码级别来分析一下该问题发生的原因以及相应的调试方法。
重现问题
首先我们先尝试重现这个问题,在ASP.NET程序web.config中有一个executionTimeout的设置,默认值为110秒,也就是说一个请求的执行时间超过110秒就会timeout从而产生HttpException
"Request Timed Out"。这个设置可以通过IIS Configuration Editor或者web.config进行更改。
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appSettings />
<connectionStrings />
<system.web>
<compilation>
</compilation>
<authentication mode="Windows" />
<httpRuntime executionTimeout="10" />
</system.web>
</configuration>
为了快速重现这个问题我们将executionTimeout默认值改为10秒。然后建立一个让请求超时的asp.net页面如下。
<%@ Page Language="C#" AutoEventWireup="true" Inherits="System.Web.UI.Page" %>
<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
System.Threading.Thread.Sleep(120000);
}
</script>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
</div>
</form>
</body>
</html>
将页面部署在IIS上,然后请求页面,等待10秒到25秒左右问题重现。
产生原理
这里有一个值得注意的地方,为什么我们页面逻辑在执行Sleep却抛出了HttpException,执行线程被谁打断了,是怎么打断的?
研究这个问题我们首先要用windbg来察看一下这个异常发生的调用栈信息。
通过windbg attach到w3wp进程,然后输入命令'sxe
clr'捕获clrfirst chance exception
CLR exception - code e0434f4d (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
KERNELBASE!RaiseException+0x68:
000007fb`bbb789cc 488b8c24c0000000 mov rcx,qword ptr [rsp+0C0h] ss:000000da`6bf0da20=38a1bff3b7640000
0:023> KL
Child-SP RetAddr Call Site
000000da`6bf0d960 000007fb`a0da98ef KERNELBASE!RaiseException+0x68
000000da`6bf0da40 000007fb`a0d03e07 mscorwks!RaiseTheExceptionInternalOnly+0x2ff
000000da`6bf0db30 000007fb`a0cc58cf mscorwks!Thread::HandleThreadAbort+0x19b
000000da`6bf0dbd0 000007fb`a0cbe815 mscorwks!Thread::HandleThreadInterrupt+0x7b
000000da`6bf0dc30 000007fb`a1280769 mscorwks!Thread::UserSleep+0x89
000000da`6bf0dc90 000007fb`415d09ee mscorwks!ThreadNative::Sleep+0xf9
000000da`6bf0de40 000007fb`41630f39 App_Web_kng1ridv!ASP.sleep120_aspx.Page_Load(System.Object, System.EventArgs)+0xe
…
000000da`6bf0fae0 000007fb`beb53501 KERNEL32!BaseThreadInitThunk+0x1a
000000da`6bf0fb10 00000000`00000000 ntdll!RtlUserThreadStart+0x21栈上面的first chanceexception为ThreadAbortException。
0:023> !dso
OS Thread Id: 0x12e0 (23)
RSP/REG Object Name
000000da6bf0d968 000000da0aac3ea0 System.Threading.ThreadAbortException
000000da6bf0da30 000000da0aac3ea0 System.Threading.ThreadAbortException
000000da6bf0da48 000000da0aac3ea0 System.Threading.ThreadAbortException
000000da6bf0db30 000000da0aac3ea0 System.Threading.ThreadAbortException
000000da6bf0dc98 000000da0aa93c90 System.Web.HttpContext
000000da6bf0dca0 000000da0aac3498 System.ComponentModel.EventHandlerList
000000da6bf0dd70 000000da0aac3498 System.ComponentModel.EventHandlerList
000000da6bf0dd90 000000da0aa93c90 System.Web.HttpContext
从这个调用栈上我们可以看出来这个异常来自于Thread::UserSleep -> Thread::HandleThreadInterrupt ->Thread::HandleThreadAbort
由于这个调用栈是CLR非托管代码,我们需要一份.NETFrameworkCLR的源代码作为参考,可以到微软下载一份Share
Source CLI。找到\sscli20_20060311\sscli20\clr\src\vm\threads.cpp这个源文件,这个类封装的一系列CLR线程相关的属性和方法。
因为我们调用了Sleep方法,首先看一下Sleep函数的实现。原来线程调用Sleep方法之后进入系统内核,内核将其置于等待状态,一旦CLRSleepEx返回WAIT_IO_COMPLETION并且通过m_State
& TS_Interrupted两个标志位来判断是interrupt的话,系统将开始执行HandleThreadInterrupt方法,进而在HandleThreadInterrupt方法中抛出ThreadAbortException。
// Implementation of Thread.Sleep().
void Thread::UserSleep(INT32 time)
{
CONTRACTL {
THROWS;
GC_TRIGGERS;
}
CONTRACTL_END;
INCONTRACT(_ASSERTE(!GetThread()->GCNoTrigger()));
DWORD res;
GCX_PREEMP();
// A word about ordering for Interrupt. If someone tries to interrupt a thread
// that's in the interruptible state, we queue an APC. But if they try to interrupt
// a thread that's not in the interruptible state, we just record that fact. So
// we have to set TS_Interruptible before we test to see whether someone wants to
// interrupt us or else we have a race condition that causes us to skip the APC.
FastInterlockOr((ULONG *) &m_State, TS_Interruptible);
// If someone has interrupted us, we should not enter the wait.
if (IsUserInterrupted())
{
HandleThreadInterrupt(FALSE);
}
ThreadStateHolder tsh(TRUE, TS_Interruptible | TS_Interrupted);
FastInterlockAnd((ULONG *) &m_State, ~TS_Interrupted);
retry:
res = ClrSleepEx (time, TRUE);
if (res == WAIT_IO_COMPLETION)
{
// We could be woken by some spurious APC or an EE APC queued to
// interrupt us. In the latter case the TS_Interrupted bit will be set
// in the thread state bits. Otherwise we just go back to sleep again.
if ((m_State & TS_Interrupted))
{
HandleThreadInterrupt(FALSE);
}
// Don't bother with accurate accounting here. Just ensure we make progress.
// Note that this is not us doing the APC.
if (time == 0)
{
res = WAIT_TIMEOUT;
}
else
{
if (time != (INT32) INFINITE)
{
time--;
}
goto retry;
}
}
_ASSERTE(res == WAIT_TIMEOUT || res == WAIT_OBJECT_0);
}
接下来一个问题是到底是什么使得ClrSleepEx方法返回了呢?根据注释我们可以看到APC很可能是打断等待线程的原因。接下来我们继续通过debug验证一下。根据msdn用户模式可以调用kernel32!QueueUserAPC方法发送一个APC到指定线程。我们在这个方法上设置一个断点然后重现这个问题。结果抓到了这个调用栈。
0:022> kL
Child-SP RetAddr Call Site
000000da`6bbfe808 000007fb`a10ce75b KERNEL32!QueueUserAPCStub
000000da`6bbfe810 000007fb`a0e37e88 mscorwks!Thread::Alert+0xdb
000000da`6bbfe880 000007fb`a103d0d4 mscorwks!Thread::UserInterrupt+0x30
000000da`6bbfe8b0 000007fb`a11f5699 mscorwks!Thread::UserAbort+0x3984d0
000000da`6bbfe9d0 000007fb`997c4519 mscorwks!ThreadNative::Abort+0x169
000000da`6bbfebd0 000007fb`988f835f mscorlib_ni!System.Threading.Thread.Abort(System.Object)+0x39
000000da`6bbfec20 000007fb`97e94547 System_Web_ni!System.Web.RequestTimeoutManager+RequestTimeoutEntry.TimeoutIfNeeded(System.DateTime)+0xa63d4f
000000da`6bbfec60 000007fb`99772bdb System_Web_ni!System.Web.RequestTimeoutManager.CancelTimedOutRequests(System.DateTime)+0x167
…
000000da`6bbff8a0 00000000`00000000 ntdll!RtlUserThreadStart+0x21
看一下栈上的信息,究竟是哪个线程正在被abort。
0:022> !dso
OS Thread Id: 0x14e4 (22)
RSP/REG Object Name
000000da6bbfe9c0 000000da0aa84400 System.Threading.Thread
000000da6bbfea28 000000d9cab1efe8 System.Web.HttpApplication+CancelModuleException
000000da6bbfea38 000000da0aa84400 System.Threading.Thread
000000da6bbfea88 000000d9caa4c810 System.String
0:022> !do 000000da0aa84400
Name: System.Threading.Thread
MethodTable: 000007fb998b86c0
EEClass: 000007fb994bea18
Size: 104(0x68) bytes
(C:\windows\assembly\GAC_64\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
Fields:
MT Field Offset Type VT Attr Value Name
000007fb998f01b0 4000690 8 ....Contexts.Context 0 instance 000000d9caa285c0 m_Context
000007fb998b2bd0 4000691 10 ....ExecutionContext 0 instance 000000da0aace570 m_ExecutionContext
000007fb998b7c20 4000692 18 System.String 0 instance 0000000000000000 m_Name
000007fb998b8438 4000693 20 System.Delegate 0 instance 0000000000000000 m_Delegate
000007fb998aefe0 4000694 28 System.Object[][] 0 instance 0000000000000000 m_ThreadStaticsBuckets
000007fb998bed40 4000695 30 System.Int32[] 0 instance 0000000000000000 m_ThreadStaticsBits
000007fb998c05a0 4000696 38 ...ation.CultureInfo 0 instance 0000000000000000 m_CurrentCulture
000007fb998c05a0 4000697 40 ...ation.CultureInfo 0 instance 0000000000000000 m_CurrentUICulture
000007fb998b7510 4000698 48 System.Object 0 instance 0000000000000000 m_ThreadStartArg
000007fb998ba628 4000699 50 System.IntPtr 1 instance
da6b789d60 DONT_USE_InternalThread
000007fb998bee90 400069a 58 System.Int32 1 instance 2 m_Priority
000007fb998bee90 400069b 5c System.Int32 1 instance 7 m_ManagedThreadId
000007fb998ac8d8 400069c 2d8 ...LocalDataStoreMgr 0 shared static s_LocalDataStoreMgr
>> Domain:Value 000000d9c90512d0:0000000000000000 000000d9ca176610:0000000000000000 <<
000007fb998b7510 400069d 2e0 System.Object 0 shared static s_SyncObject
>> Domain:Value 000000d9c90512d0:000000d9caa23bf0 000000d9ca176610:000000da0aa2d410 <<
0:022> !threads
ThreadCount: 10
UnstartedThread: 0
BackgroundThread: 9
PendingThread: 0
DeadThread: 1
Hosted Runtime: no
PreEmptive Lock
ID OSID ThreadOBJ State GC GC Alloc Context Domain Count APT Exception
3 1 150c 000000d9ca125a90 8220 Enabled 0000000000000000:0000000000000000 000000d9c90512d0 0 Ukn
19 2 23c8 000000d9ca12f510 b220 Enabled 000000da0aa8a238:000000da0aa8c200 000000d9c90512d0 0 MTA (Finalizer)
20 3 1a98 000000d9ca174ab0 80a220 Enabled 0000000000000000:0000000000000000 000000d9c90512d0 0 MTA (Threadpool Completion Port)
21 4 23f4 000000d9ca175b60 1220 Enabled 0000000000000000:0000000000000000 000000d9c90512d0 0 Ukn
22 5 14e4 000000da6b779c50 180b220 Disabled 000000d9cab1f000:000000d9cab20b18 000000d9ca176610 1 MTA (Threadpool Worker)
XXXX 6 0 000000da6b77d9d0 10820 Enabled 0000000000000000:0000000000000000 000000d9c90512d0 0 Ukn
23 7 12e0 000000da6b789d60
3a0b221 Enabled 000000da0aafd860:000000da0aafe2a8 000000d9ca176610 1 MTA (Threadpool Worker)
15 8 2180 000000da6b78a330 880a220 Enabled 0000000000000000:0000000000000000 000000d9c90512d0 0 MTA (Threadpool Completion Port)
24 9 13a4 000000da6b7903a0 220 Enabled 000000d9caae2e48:000000d9caae4aa8 000000d9c90512d0 0 Ukn
25 a e5c 000000d9ca107180 220 Enabled 000000d9cab20c68:000000d9cab22b18 000000d9c90512d0 0 Ukn
结果我们看到是23号线程是被abort的目标。23号线程正在做什么?查看23号线程调用栈正好是我们的Sleep方法线程。
0:023> kL
Child-SP RetAddr Call Site
000000da`6bf0db08 000007fb`bbb611f2 ntdll!NtDelayExecution+0xa
000000da`6bf0db10 000007fb`a10c369d KERNELBASE!SleepEx+0xaa
000000da`6bf0dbb0 000007fb`a0cbe7fd mscorwks!EESleepEx+0x2d
000000da`6bf0dc30 000007fb`a1280769 mscorwks!Thread::UserSleep+0x71
000000da`6bf0dc90 000007fb`415d09ee mscorwks!ThreadNative::Sleep+0xf9
000000da`6bf0de40 000007fb`41630f39
App_Web_kng1ridv!ASP.sleep120_aspx.Page_Load(System.Object, System.EventArgs)+0xe
…
000000da`6bf0f750 000007fb`a0d1970a mscorwks!UnManagedPerAppDomainTPCount::DispatchWorkItem+0x157
000000da`6bf0f7f0 000007fb`a0dcf3a4 mscorwks!ThreadpoolMgr::WorkerThreadStart+0x1ba
000000da`6bf0f890 000007fb`bc53167e mscorwks!Thread::intermediateThreadProc+0x78
000000da`6bf0fae0 000007fb`beb53501 KERNEL32!BaseThreadInitThunk+0x1a
000000da`6bf0fb10 00000000`00000000 ntdll!RtlUserThreadStart+0x21
到此我们可以证明我们的想法了,原来ASP.NET启动了一个RequestTimeoutManager来负责查看超时线程,然后通过发送APC的方式打断超时线程使之抛出ThreadAbortException结束等待,最后ThreadAbortException被包装成HttpException抛出,记录在日志以及显示在客户端。
调试方法
现实过程中Timeout不一定是出在线程Sleep上,也不是所有的ThreadAbortException都代表Timeout的问题发生。我们还是要总结一下类似问题的调试方法。
第一,观察timeout的时间,是否是100秒左右,与配置中的数值是否相符(注意这里比一定是一秒不差,因为查看RequestTimeoutManager逻辑可以发现他是每隔15秒查看一下超时线程,所有存在15秒左右的误差。
第二,如果不是超时时间设置过小的原因,那就要通过抓dump的方式来查看具体的超时请求超时在什么操作上。因为我们最终得到的ThreadAbortException中没有调用栈信息。
如何抓到对的dump是个值得研究的问题,我们可以把断点设在以下调用栈上的某个点上,注意断点越接近栈顶,这个方法可能被调用的次数就越多,抓到没有用的dump的可能性越大。
0:022> kL
Child-SP RetAddr Call Site
000000da`6bbfe808 000007fb`a10ce75b KERNEL32!QueueUserAPCStub
000000da`6bbfe810 000007fb`a0e37e88 mscorwks!Thread::Alert+0xdb
000000da`6bbfe880 000007fb`a103d0d4 mscorwks!Thread::UserInterrupt+0x30
000000da`6bbfe8b0 000007fb`a11f5699 mscorwks!Thread::UserAbort+0x3984d0
000000da`6bbfe9d0 000007fb`997c4519 mscorwks!ThreadNative::Abort+0x169
000000da`6bbfebd0 000007fb`988f835f mscorlib_ni!System.Threading.Thread.Abort(System.Object)+0x39
000000da`6bbfec20 000007fb`97e94547 System_Web_ni!System.Web.RequestTimeoutManager+RequestTimeoutEntry.TimeoutIfNeeded(System.DateTime)+0xa63d4f
000000da`6bbfec60 000007fb`99772bdb System_Web_ni!System.Web.RequestTimeoutManager.CancelTimedOutRequests(System.DateTime)+0x167
…
000000da`6bbff8a0 00000000`00000000 ntdll!RtlUserThreadStart+0x21
通过ILSpy查看CancelTimedOutRequests和TimeoutIfNeeded源代码,可以看到进入这个方法并不一定代表有线程会被abort,所以我们要从下面一层抓。最终结论是如果我们想要研究Timeout的ThreadAbortException,我们可以在mscorlib_ni!System.Threading.Thread.Abort上面设置断点抓dump,然后查看堆栈上面的线程,最终找到正在被abort的线程以及相应执行的调用栈信息。
// System.Web.RequestTimeoutManager
privatevoidCancelTimedOutRequests(DateTime now)
{
if(Interlocked.CompareExchange(refthis._inProgressLock,1,0)!=0)
{
return;
}
ArrayList arrayList =newArrayList(this._requestCount);
for(inti =0;i<this._lists.Length;i++)
{
DoubleLinkList obj;
Monitor.Enter(obj =this._lists[i]);
try
{
DoubleLinkListEnumerator enumerator =this._lists[i].GetEnumerator();
while(enumerator.MoveNext())
{
arrayList.Add(enumerator.GetDoubleLink());
}
}
finally
{
Monitor.Exit(obj);
}
}
intcount = arrayList.Count;
for(intj =0;j<count;j++)
{
((RequestTimeoutManager.RequestTimeoutEntry)arrayList[j]).TimeoutIfNeeded(now);
}
Interlocked.Exchange(refthis._inProgressLock,0);
}
// System.Web.RequestTimeoutManager.RequestTimeoutEntry
internalvoidTimeoutIfNeeded(DateTime now)
{
Thread thread =this._context.MustTimeout(now);
if(thread!=null)
{
this.RemoveFromList();
thread.Abort(newHttpApplication.CancelModuleException(true));
}
}
分享到:
相关推荐
发卡系统源码无授权版 带十多套模板
STM32F103系列PWM输出应用之纸短情长音乐——无源蜂鸣器
基于matlab开发的rvm回归预测 RVM采取是与支持向量机相同的函数形式稀疏概率模型,对未知函数进行预测或分类.rar
STM32工具 CubeMX 使用FreeRtos系统 基于lwRB通用环形缓冲区的串口非阻塞发送,程序使用printf,通过重定向fputc函数,将发送数据保存在FIFO中,可以在中断中调用printf,保证了系统的线程安全和中断安全,将发送任务放在线程中。LwRB有两个指针一个r读指,一个w写指针,底层采用原子操作,不需要用到锁,保证了线程安全,最大的好处是它是支持DMA的,为CPU减负。
EasyJF官网全站源码_easyjfcom_src.rar是一个针对计算机专业的JSP源码资料包,它包含了丰富的内容和功能,旨在帮助开发人员快速构建和管理网站。这个源码包基于Java技术栈,使用JSP(JavaServer Pages)作为前端页面渲染技术,结合了Servlet、JavaBean等后端组件,为开发者提供了一个稳定、高效的开发环境。通过使用这个源码包,开发者可以快速搭建一个具有基本功能的网站建设平台。它提供了用户注册、登录、权限管理等基本功能,同时也支持文章发布、分类管理、评论互动等常见内容管理操作。此外,源码包还包含了一些实用的辅助工具,如文件上传、数据导出等,方便开发者进行网站的维护和管理。在界面设计方面,EasyJF官网全站源码采用了简洁、易用的设计风格,使得用户可以轻松上手并进行个性化定制。同时,它还提供了一些可扩展的插件和模板,开发者可以根据自己的需求进行修改和扩展,实现更多的功能和效果。总之,EasyJF官网全站源码_easyjfcom_src.rar是一个功能强大、易于使用的计算机专业JSP源码资料包,适用于各类网站建设项目。无论是初学者还是有经验的开发者
Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。
Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。
Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。
基于matlab实现此压缩包包含语音信号处理中的语音变声代码加音频.rar
Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。
使用 Base64 编码来对 UUID(Universally Unique Identifiers) 存储在一些特定的场合被广泛的使用。使用 Base64 对比直接使用 UUID 进行存储来说能够更多的节约空间。 本文对这方面的相关内容和问题进行探讨。 在这里,使用 Base64 来对 UUID 进行存储,涉及到一些类型的转换的。Base64 是编码算法,在实际使用的时候我们更多会用到 Byte 数组的方式来进行编码的。这样我们就比较明确在对其进行 Base64 转换之前,我们应该要先干什么了。
Java网络爬虫(蜘蛛)源码.zip
这是Pandas基础学习
架构 主微控制器采用 STM32F103C8T6。 目前外设部分包括: 显示模块:0.96寸4针IIC通信协议的OLED模块 温湿度采集模块:DHT11 网络通信模块:ESP8266 报警模块:高电平触发的有缘蜂鸣器 其他:若干LED灯珠以及若干贴片按键 硬件端系统使用C语言编写
新版PHP无陌然在线云加密平台系统源码 带安装说明.rar新版PHP无陌然在线云加密平台系统源码 带安装说明.rar
近年来由于生活节奏的加快,好像每个人都被很多难以启齿的问题困惑,然而关于随意消费是大多数人头疼的问题,没有任何计划和筹备的情况下随意消费,导致现实生活中我们所称为的“月光族”。 当你逐渐了解自己的财务状况,就可以学着做简单的收支规划。大部分月光族的根源其实是缺乏规划,想买什么的时候就买了。并不是说规划不能随意买东西,规划的价值在于让你使用资金的效率最高。无论你用金钱换取的必需品,满足感或者快乐,都可以通过规划获得比较高的效率。 本记账系统是一个基于国内外电子商务网站的发展现状,采用B2C(Business to Consumers)模式开发的电子商务平台,它的价值所在对于那些随意消费性的人群能起到一个很大的警示作用,而且系统扩张性很强,能根据客户的不同需求进行快速改进。该系统采用B/S三层结构,服务器是Tomcat同时运用JSp技术进行动态页面设计,后台数据库是Oracle。
最新微信文章编辑器排版工具程序源码.rar最新微信文章编辑器排版工具程序源码.rar最新微信文章编辑器排版工具程序源码.rar
前台方面(经营者用户): 系统首页:是用这户端的系统首页,首页的最上方有投诉建议、进入后台等选项,页面下方可以根据商品编号进行商品状态的实时查询,十分方便快捷。 投诉建议:用户可以在这个系统的这个板块给系统开发者留言,向开发者反应系统使用者的疑难问题,并提出自己相应的改进建议。 商品入库:生鲜商品经营者可以在商品入库界面,对一定数量的生鲜商品进行入库操作,确保库房内的每一件商品都能追根溯源,保障产品质量安全。 商品出库:用户在商品出库界面,可以对指定的商品进行出库操作,输入出库数量,点击提交即可。 商品列表:用户还可以在商品列表的界面中,对自己旗下生鲜商品的入库、出库情况进行实时查看。 后台方面(管理者用户): 商品管理:商品管理是系统后台的核心功能,在这个功能模块中,系统管理员可以对平台内生鲜商品的出入库指令进行严格的审核,并且可以对商品的归属地追根溯源。 经营者管理:拥有最高管理权限的系统管理员,可以连接到数据库,对经营者类别、名称、经营许可证编号等基础信息进行审核。 投诉建议管理:管理员还可以对所有注册用户的投诉建议,进行删除或者回复操作,通过这种方式,与注册用户进行线上交流。
MyBatis 是一个持久层框架,它允许用户在 XML 文件中编写动态 SQL 语句。MyBatis 的动态 SQL 功能非常强大,它允许开发者根据运行时的条件动态地生成 SQL 语句。这使得 MyBatis 能够灵活地处理各种复杂的查询需求。 MyBatis 动态 SQL 通过使用 <if>、<choose>、<when>、<otherwise>、<trim>、<set> 等标签来实现。附件中是一些常见的动态 SQL 标签及其用法,通过组合使用这些标签,可以编写出非常灵活和强大的 SQL 语句,以适应不同的查询和更新需求