[netty5: MessageAggregator HttpObjectAggregator]-源码解析

在阅读这篇文章前,推荐先阅读

  1. [netty5: ByteToMessageCodec & MessageToByteEncoder & ByteToMessageDecoder]-源码分析
  2. [netty5: HttpObject]-源码解析

100-continue

100-continue 是 HTTP/1.1 协议中的一种机制,用于客户端在发送大体积请求体(如文件上传)前,先向服务器发送一个带有 Expect: 100-continue 头的请求,询问服务器是否准备好接收请求体;服务器如果准备好了,会返回 100 Continue 响应,客户端才开始发送实际数据,从而避免不必要的大数据传输。

MessageAggregator

MessageAggregator<I, S, C, A> 是一个高度可复用的通用聚合器框架,适用于各种流式协议的“分段消息聚合”场景:

功能说明
启动聚合tryStartMessage() 检测到起始消息,初始化聚合
聚合中tryContentMessage() 检测到内容消息,append 内容
完成聚合isLastContentMessage() 判断是否是最后一块,调用 finishAggregation
超长控制maxContentLength + lengthForContent 控制体积
特殊控制支持 100-continue、异常处理、复用 context listener
public abstract class MessageAggregator<I, S, C extends AutoCloseable, A extends AutoCloseable> extends MessageToMessageDecoder<I> {// 当前正在聚合的完整消息(例如 FullHttpRequest 或 FullHttpResponse)private A currentMessage;// 聚合内容允许的最大字节数,超过则触发 handleOversizedMessageprivate final int maxContentLength;// 标识当前是否正在处理超长消息,避免重复处理。private boolean handlingOversizedMessage;private ChannelHandlerContext ctx;// 用于监听 100-Continue 响应写入完成后的回调private FutureContextListener<ChannelHandlerContext, Void> continueResponseWriteListener;// 标识是否正在聚合过程中private boolean aggregating;// 是否在通道关闭时处理未完成的聚合private boolean handleIncompleteAggregateDuringClose = true;protected MessageAggregator(int maxContentLength) {this.maxContentLength = maxContentLength;}@Overridepublic boolean acceptInboundMessage(Object msg) throws Exception {if (!super.acceptInboundMessage(msg)) {return false;}if (isAggregated(msg)) {return false;}if (tryStartMessage(msg) != null) {return true;}return aggregating && tryContentMessage(msg) != null;}@Overrideprotected void decode(final ChannelHandlerContext ctx, I msg) throws Exception {// 1. 判断是否为新消息起始(startMsg)// 判断当前收到的 msg 是否为 HttpMessage,如果是,则开始处理聚合。final S startMsg = tryStartMessage(msg);if (startMsg != null) {aggregating = true;handlingOversizedMessage = false;// 如果已存在未完成的 currentMessage,说明消息异常,抛出 MessageAggregationExceptionif (currentMessage != null) {currentMessage.close();currentMessage = null;throw new MessageAggregationException();}// 2. 处理 100-continue 相关响应(continueResponse)// newContinueResponse 的核心逻辑:// - 如果请求头中包含 Expect: 100-continue,并且请求体大小没有超过 maxContentLength,则返回一个 100 Continue 响应;// - 如果请求体过大(Content-Length > maxContentLength),则返回一个 413 Request Entity Too Large 错误响应;// - 如果不符合任何条件,返回 null,表示不需要继续响应。Object continueResponse = newContinueResponse(startMsg, maxContentLength, ctx.pipeline());if (continueResponse != null) {// 构造监听器FutureContextListener<ChannelHandlerContext, Void> listener = continueResponseWriteListener;if (listener == null) {continueResponseWriteListener = listener = (context, future) -> {if (future.isFailed()) {context.fireChannelExceptionCaught(future.cause());}};}// 判断在收到 100-continue 响应后是否关闭连接,条件是配置了关闭标志且响应表示应忽略后续内容。boolean closeAfterWrite = closeAfterContinueResponse(continueResponse);// 	// 判断响应是否为客户端错误(4xx),如果是,则说明应忽略后续内容。handlingOversizedMessage = ignoreContentAfterContinueResponse(continueResponse);// 写出响应并监听结果Future<Void> future = ctx.writeAndFlush(continueResponse).addListener(ctx, listener);if (closeAfterWrite) {handleIncompleteAggregateDuringClose = false;future.addListener(ctx, ChannelFutureListeners.CLOSE);return;}// 判断是否忽略后续内容if (handlingOversizedMessage) {return;}} else if (isContentLengthInvalid(startMsg, maxContentLength)) {// 3. 检查请求长度是否合法invokeHandleOversizedMessage(ctx, startMsg);return;}// 4. 处理起始消息中已有的解码失败情况if (startMsg instanceof DecoderResultProvider &&!((DecoderResultProvider) startMsg).decoderResult().isSuccess()) {final A aggregated = beginAggregation(ctx.bufferAllocator(), startMsg);finishAggregation(ctx.bufferAllocator(), aggregated);ctx.fireChannelRead(aggregated);return;}// 5. 初始化新消息聚合对象// 创建一个聚合消息实例(包含起始行和一个空的内容缓冲区),等待后续内容片段加入。currentMessage = beginAggregation(ctx.bufferAllocator(), startMsg);return;}// 6. 处理内容消息(contentMsg)// 先判断 msg 是否是消息体片段,如果不是则抛异常。final C contentMsg = tryContentMessage(msg);if (contentMsg != null) {// 如果还没有初始化的聚合消息(即没有起始消息),忽略该内容。if (currentMessage == null) {return;}// 检查聚合后长度是否超限,超限则调用超长消息处理。if (lengthForAggregation(currentMessage) > maxContentLength - lengthForContent(contentMsg)) {invokeHandleOversizedMessage(ctx, currentMessage);return;}// 调用 aggregate 将当前内容片段追加到聚合消息。aggregate(ctx.bufferAllocator(), currentMessage, contentMsg);final boolean last;// 检查是否为消息最后一片(last)if (contentMsg instanceof DecoderResultProvider) {DecoderResult decoderResult = ((DecoderResultProvider) contentMsg).decoderResult();if (!decoderResult.isSuccess()) {if (currentMessage instanceof DecoderResultProvider) {((DecoderResultProvider) currentMessage).setDecoderResult(DecoderResult.failure(decoderResult.cause()));}last = true;} else {last = isLastContentMessage(contentMsg);}} else {last = isLastContentMessage(contentMsg);}// 如果是,完成聚合,清理状态,向下游传递完整消息。if (last) {finishAggregation0(ctx.bufferAllocator(), currentMessage);// All doneA message = currentMessage;currentMessage = null;ctx.fireChannelRead(message);}} else {throw new MessageAggregationException();}}@Overridepublic void channelReadComplete(ChannelHandlerContext ctx) throws Exception {if (currentMessage != null && !ctx.channel().getOption(ChannelOption.AUTO_READ)) {ctx.read();}ctx.fireChannelReadComplete();}@Overridepublic void channelInactive(ChannelHandlerContext ctx) throws Exception {if (aggregating && handleIncompleteAggregateDuringClose) {ctx.fireChannelExceptionCaught(new PrematureChannelClosureException("Channel closed while still aggregating message"));}try {super.channelInactive(ctx);} finally {releaseCurrentMessage();}}@Overridepublic void handlerAdded(ChannelHandlerContext ctx) throws Exception {this.ctx = ctx;}@Overridepublic void handlerRemoved(ChannelHandlerContext ctx) throws Exception {try {super.handlerRemoved(ctx);} finally {releaseCurrentMessage();}}protected final void releaseCurrentMessage() throws Exception {if (currentMessage != null) {currentMessage.close();currentMessage = null;}handlingOversizedMessage = false;aggregating = false;}// 省略抽象方法,具体看 HttpObjectAggregator
}

HttpObjectAggregator

HttpObjectAggregator 是构建高层 HTTP 服务的基础设施组件,它将分块的 HTTP 请求或响应组装为完整对象,从而简化上层应用逻辑。其设计清晰、可扩展性强,并充分考虑了 Expect: 100-continue 与 Content-Length 异常等 HTTP 协议边界情况,是非常值得借鉴的聚合处理器实现。

public class HttpObjectAggregator<C extends HttpContent<C>>extends MessageAggregator<HttpObject, HttpMessage, HttpContent<C>, FullHttpMessage<?>> {private static final Logger logger = LoggerFactory.getLogger(HttpObjectAggregator.class);// 当检测到客户端发送了 100-continue 期望但请求内容过大时,是否关闭连接;// 为 true 则直接关闭连接,防止浪费资源,// 为 false 则保持连接打开并继续读取和丢弃数据直到下一请求。private final boolean closeOnExpectationFailed;public HttpObjectAggregator(int maxContentLength) {this(maxContentLength, false);}public HttpObjectAggregator(int maxContentLength, boolean closeOnExpectationFailed) {super(maxContentLength);this.closeOnExpectationFailed = closeOnExpectationFailed;}@Overrideprotected HttpMessage tryStartMessage(Object msg) {return msg instanceof HttpMessage ? (HttpMessage) msg : null;}@SuppressWarnings("unchecked")@Overrideprotected HttpContent<C> tryContentMessage(Object msg) {return msg instanceof HttpContent ? (HttpContent<C>) msg : null;}@Overrideprotected boolean isAggregated(Object msg) throws Exception {return msg instanceof FullHttpMessage;}@Overrideprotected int lengthForContent(HttpContent<C> msg) {return msg.payload().readableBytes();}@Overrideprotected int lengthForAggregation(FullHttpMessage<?> msg) {return msg.payload().readableBytes();}@Overrideprotected boolean isLastContentMessage(HttpContent<C> msg) throws Exception {return msg instanceof LastHttpContent;}@Overrideprotected boolean isContentLengthInvalid(HttpMessage start, int maxContentLength) {try {return getContentLength(start, -1L) > maxContentLength;} catch (final NumberFormatException e) {return false;}}// 根据请求的 Expectation 头判断是否返回 100 Continue 或错误响应(如 417 或 413),并在不支持或内容过大时触发相应事件private static FullHttpResponse continueResponse(HttpMessage start, int maxContentLength, ChannelPipeline pipeline) {// 根据请求的 Expectation 头判断是否支持期望,若不支持触发失败事件返回 417;if (HttpUtil.isUnsupportedExpectation(start)) {pipeline.fireChannelInboundEvent(HttpExpectationFailedEvent.INSTANCE);return newErrorResponse(EXPECTATION_FAILED, pipeline.channel().bufferAllocator(), true, false);}if (HttpUtil.is100ContinueExpected(start)) {// 若期望 100-continue 且内容长度未超限,返回 100 Continue 响应,if (getContentLength(start, -1L) <= maxContentLength) {return newErrorResponse(CONTINUE, pipeline.channel().bufferAllocator(), false, false);}// 否则触发失败事件并返回 413 请求体过大响应。pipeline.fireChannelInboundEvent(HttpExpectationFailedEvent.INSTANCE);return newErrorResponse(REQUEST_ENTITY_TOO_LARGE, pipeline.channel().bufferAllocator(), true, false);}return null;}// 根据请求创建一个 100-continue 响应,并在响应生成后移除请求中的 Expect 头。@Overrideprotected Object newContinueResponse(HttpMessage start, int maxContentLength, ChannelPipeline pipeline) {FullHttpResponse response = continueResponse(start, maxContentLength, pipeline);if (response != null) {start.headers().remove(EXPECT);}return response;}// 判断在收到 100-continue 响应后是否关闭连接,条件是配置了关闭标志且响应表示应忽略后续内容。@Overrideprotected boolean closeAfterContinueResponse(Object msg) {return closeOnExpectationFailed && ignoreContentAfterContinueResponse(msg);}// 判断响应是否为客户端错误(4xx),如果是,则说明应忽略后续内容。@Overrideprotected boolean ignoreContentAfterContinueResponse(Object msg) {if (msg instanceof HttpResponse) {final HttpResponse httpResponse = (HttpResponse) msg;return httpResponse.status().codeClass() == HttpStatusClass.CLIENT_ERROR;}return false;}// 开始对一个非完整的 HTTP 消息进行聚合,移除分块传输编码标记,并创建一个对应请求或响应类型的空聚合消息,准备接收后续内容。@Overrideprotected FullHttpMessage<?> beginAggregation(BufferAllocator allocator, HttpMessage start) throws Exception {assert !(start instanceof FullHttpMessage);// 移除 HTTP 消息头中的 Transfer-Encoding: chunked,以便后续使用聚合后的 Content-LengthHttpUtil.setTransferEncodingChunked(start, false);final CompositeBuffer content = allocator.compose();FullHttpMessage<?> ret;// 根据消息类型创建对应的聚合消息并初始化其 payload 为一个可扩展的空 CompositeBuffer,用于后续追加内容块。if (start instanceof HttpRequest) {ret = new AggregatedFullHttpRequest((HttpRequest) start, content, null);} else if (start instanceof HttpResponse) {ret = new AggregatedFullHttpResponse((HttpResponse) start, content, null);} else {throw new Error();}return ret;}// 将内容块追加到聚合消息中,并在遇到最后一块时设置尾部头信息@Overrideprotected void aggregate(BufferAllocator allocator, FullHttpMessage<?> aggregated, HttpContent<C> content) throws Exception {final CompositeBuffer payload = (CompositeBuffer) aggregated.payload();payload.extendWith(content.payload().send());if (content instanceof LastHttpContent) {((AggregatedFullHttpMessage<?>) aggregated).setTrailingHeaders(((LastHttpContent<?>) content).trailingHeaders());}}// 完成聚合时,如果未设置 Content-Length,则自动设置为聚合内容的实际长度。@Overrideprotected void finishAggregation(BufferAllocator allocator, FullHttpMessage<?> aggregated) throws Exception {if (!HttpUtil.isContentLengthSet(aggregated)) {aggregated.headers().set(CONTENT_LENGTH, String.valueOf(aggregated.payload().readableBytes()));}}// 处理超大 HTTP 消息@Overrideprotected void handleOversizedMessage(final ChannelHandlerContext ctx, Object oversized) throws Exception {if (oversized instanceof HttpRequest) {HttpRequest request = (HttpRequest) oversized;// 条件1:如果是完整请求(FullHttpMessage)或者请求既不期待100-continue也不保持连接if (oversized instanceof FullHttpMessage || !HttpUtil.is100ContinueExpected(request) && !HttpUtil.isKeepAlive(request)) {// 发送带关闭连接指示的413错误响应Future<Void> future = ctx.writeAndFlush(newErrorResponse(REQUEST_ENTITY_TOO_LARGE, ctx.bufferAllocator(), true, true));future.addListener(f -> {if (f.isFailed()) {// 日志打印发送失败的原因logger.debug("Failed to send a 413 Request Entity Too Large.", f.cause());}// 响应发送后关闭连接ctx.close();});} else {// 条件2:请求期待100-continue或者保持连接时,发送不关闭连接的413响应ctx.writeAndFlush(newErrorResponse(REQUEST_ENTITY_TOO_LARGE, ctx.bufferAllocator(), true, false)).addListener(future -> {if (future.isFailed()) {// 发送失败时日志记录并关闭连接logger.debug("Failed to send a 413 Request Entity Too Large.", future.cause());ctx.close();}});}} else if (oversized instanceof HttpResponse) {// 如果是超大的响应,直接抛出异常,可能交由上层处理throw new ResponseTooLargeException("Response entity too large: " + oversized);} else {// 既不是请求也不是响应,视为非法状态,抛异常throw new IllegalStateException();}}@Overridepublic void channelExceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {super.channelExceptionCaught(ctx, cause);if (cause instanceof ResponseTooLargeException) {ctx.close();}}// 该方法用于生成一个指定状态码的空响应,并根据参数决定是否关闭连接和设置内容长度private static FullHttpResponse newErrorResponse(HttpResponseStatus status, BufferAllocator allocator, boolean emptyContent, boolean closeConnection) {// 根据传入的状态码 status,创建一个空内容的 FullHttpResponse,FullHttpResponse resp = new DefaultFullHttpResponse(HTTP_1_1, status, allocator.allocate(0));// 如果 emptyContent 为 true,则设置响应头 Content-Length 为 0,if (emptyContent) {resp.headers().set(CONTENT_LENGTH, HttpHeaderValues.ZERO);}// 如果 closeConnection 为 true,则设置响应头 Connection: close,表示连接关闭。if (closeConnection) {resp.headers().set(CONNECTION, HttpHeaderValues.CLOSE);}return resp;}
}

AggregatedFullHttpMessage

private abstract static class AggregatedFullHttpMessage<R extends FullHttpMessage<R>> implements FullHttpMessage<R> {protected final HttpMessage message;private final Buffer payload;private HttpHeaders trailingHeaders;AggregatedFullHttpMessage(HttpMessage message, Buffer payload, HttpHeaders trailingHeaders) {this.message = message;this.payload = payload;this.trailingHeaders = trailingHeaders;}@Overridepublic void close() {payload.close();}@Overridepublic boolean isAccessible() {return payload.isAccessible();}@Overridepublic Buffer payload() {return payload;}@Overridepublic HttpHeaders trailingHeaders() {HttpHeaders trailingHeaders = this.trailingHeaders;return requireNonNullElse(trailingHeaders, HttpHeaders.emptyHeaders());}void setTrailingHeaders(HttpHeaders trailingHeaders) {this.trailingHeaders = trailingHeaders;}@Overridepublic HttpVersion getProtocolVersion() {return message.protocolVersion();}@Overridepublic HttpVersion protocolVersion() {return message.protocolVersion();}@Overridepublic FullHttpMessage<R> setProtocolVersion(HttpVersion version) {message.setProtocolVersion(version);return this;}@Overridepublic HttpHeaders headers() {return message.headers();}@Overridepublic DecoderResult decoderResult() {return message.decoderResult();}@Overridepublic void setDecoderResult(DecoderResult result) {message.setDecoderResult(result);}
}

AggregatedFullHttpRequest

private static final class AggregatedFullHttpRequest extends AggregatedFullHttpMessage<FullHttpRequest> implements FullHttpRequest {AggregatedFullHttpRequest(HttpRequest request, Buffer content, HttpHeaders trailingHeaders) {super(request, content, trailingHeaders);}@Overridepublic Send<FullHttpRequest> send() {return payload().send().map(FullHttpRequest.class,p -> new AggregatedFullHttpRequest(this, p, trailingHeaders()));}@Overridepublic AggregatedFullHttpRequest copy() {return new AggregatedFullHttpRequest(this, payload().copy(), trailingHeaders().copy());}@Overridepublic FullHttpRequest touch(Object hint) {payload().touch(hint);return this;}@Overridepublic FullHttpRequest setMethod(HttpMethod method) {((HttpRequest) message).setMethod(method);return this;}@Overridepublic FullHttpRequest setUri(String uri) {((HttpRequest) message).setUri(uri);return this;}@Overridepublic HttpMethod method() {return ((HttpRequest) message).method();}@Overridepublic String uri() {return ((HttpRequest) message).uri();}@Overridepublic FullHttpRequest setProtocolVersion(HttpVersion version) {super.setProtocolVersion(version);return this;}@Overridepublic String toString() {return HttpMessageUtil.appendFullRequest(new StringBuilder(256), this).toString();}
}

AggregatedFullHttpResponse

private static final class AggregatedFullHttpResponse extends AggregatedFullHttpMessage<FullHttpResponse> implements FullHttpResponse {AggregatedFullHttpResponse(HttpResponse message, Buffer content, HttpHeaders trailingHeaders) {super(message, content, trailingHeaders);}@Overridepublic Send<FullHttpResponse> send() {return payload().send().map(FullHttpResponse.class,p -> new AggregatedFullHttpResponse(this, p, trailingHeaders()));}@Overridepublic AggregatedFullHttpResponse copy() {return new AggregatedFullHttpResponse(this, payload().copy(), trailingHeaders().copy());}@Overridepublic FullHttpResponse touch(Object hint) {payload().touch(hint);return this;}@Overridepublic FullHttpResponse setStatus(HttpResponseStatus status) {((HttpResponse) message).setStatus(status);return this;}@Overridepublic HttpResponseStatus status() {return ((HttpResponse) message).status();}@Overridepublic FullHttpResponse setProtocolVersion(HttpVersion version) {super.setProtocolVersion(version);return this;}@Overridepublic String toString() {return HttpMessageUtil.appendFullResponse(new StringBuilder(256), this).toString();}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/90314.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/90314.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前端学习1--行内元素 vs 块级元素(基础概念+案例实操)

一、内外边距学习&#xff1a;&#xff08;1&#xff09;简单理解&#xff1a;padding为内边距。padding不会影响元素的位置&#xff0c;只会调整元素的内容&#xff08;文字&#xff09;与边框之间的间距。margin为外边距。margin会影响元素在流式布局中的位置&#xff0c;改变…

Express + mysql2 + jwt 实现简单的登录鉴权

目前项目中使用Express 实现简单API功能&#xff0c;需要提供一套登录鉴权方案。这边是API侧实现 相关路由的登录鉴权。大体思路&#xff1a;就是&#xff0c;登录接口中通过jwt加密 token返回前端&#xff0c;前端其他接口把加密好的放入请求头Authorization中。中间件通过请求…

ReAct (Reason and Act) OR 强化学习(Reinforcement Learning, RL)

这个问题触及了现代AI智能体&#xff08;Agent&#xff09;构建的两种核心思想。 简单来说&#xff0c;ReAct 是一种“调用专家”的模式&#xff0c;而强化学习 (RL) 是一种“从零试错”的模式。 为了让你更清晰地理解&#xff0c;我们从一个生动的比喻开始&#xff0c;然后进行…

iTwinjs 4.10-4.11 更新

撤销更改 目前&#xff0c;撤销一个有缺陷的变更集的唯一方法是从 iModel Hub 中移除它&#xff0c;这可能会导致许多副作用&#xff08;无法撤销&#xff09;。一个更好的方法是在时间线中撤销变更集&#xff0c;并将其作为新的变更集引入。尽管这种方法仍然具有侵入性&#…

【CSS-15】深入理解CSS transition-duration:掌握过渡动画的时长控制

在现代网页设计中&#xff0c;平滑的过渡效果是提升用户体验的关键因素之一。CSS transitions 为我们提供了一种简单而强大的方式来实现元素在不同状态之间的平滑过渡&#xff0c;而 transition-duration 属性则是控制这些过渡效果时长的核心工具。本文将全面探讨 transition-d…

mysql-笔记

1. 安装mysql # 使用brew安装 brew install mysql# 查看是否安装成功 mysql -V 相关文档&#xff1a; mac&#xff1a;macOS下MySQL 8.0 安装与配置教程 - KenTalk - 博客园 Linux安装&#xff1a;linux安装mysql客户端_linux mysql 客户端-CSDN博客 2. 启动mysql 每次使…

Spring Boot启动优化7板斧(延迟初始化、组件扫描精准打击、JVM参数调优):砍掉70%启动时间的魔鬼实践

Spring Boot启动优化7板斧&#xff1a;砍掉70%启动时间的魔鬼实践1. 延迟初始化&#xff1a;按需加载的智慧2. 组件扫描精准打击&#xff1a;告别无差别扫描3. JVM参数调优&#xff1a;启动加速的隐藏开关4. 自动配置瘦身&#xff1a;砍掉Spring Boot的"赘肉"5. 类加…

从0开始学习计算机视觉--Day08--卷积神经网络

之前我们提到&#xff0c;神经网络是通过全连接层对输入做降维处理&#xff0c;将输入的向量通过矩阵和激活函数进行降维&#xff0c;在神经元上输出激活值。而卷积神经网络中&#xff0c;用卷积层代替了全连接层。 不同的是&#xff0c;这里的输入不再需要降维&#xff0c;而…

解决阿里云ubuntu内存溢出导致vps死机无法访问 - 永久性增加ubuntu的swap空间 - 阿里云Linux实例内存溢出(OOM)问题修复方案

效果图报错通过对实例当前截屏的分析发现&#xff0c;实例因 Linux实例内存空间不足&#xff0c;导致操作系统出现内存溢出&#xff08;OOM&#xff09; 无法正常启动。请您根据 Code&#xff1a;1684829582&#xff0c;在文档中查询该问题对应的修复方案&#xff0c;并通过VNC…

Serverless JManus: 企业生产级通用智能体运行时

作者&#xff1a;丛霄、陆龟 概述&#xff1a;本文介绍如何使用 JManus 框架构建通用智能体应用&#xff0c;部署并运行在 Serverless 运行时&#xff0c;构建企业级高可用智能体应用的实践经验。基于阿里云 Serverless 应用引擎SAE 运行稳定高可用的智能体应用&#xff0c; 基…

MySQL的数据目录

导读&#xff1a;根据前面的所学知识&#xff0c;我们知道了InnoDB存储引擎存储数据的数据结构、存储过程&#xff0c;而被组织好的数据则被存储在操作系统的磁盘上&#xff0c;当我们在对表数据进行增删改查时&#xff0c;其实就是InnoDB存储引擎与磁盘的交互。此外&#xff0…

Web前端开发: :has功能性伪类选择器

:has功能性伪类选择器::has() 是 CSS 中的一个功能性伪类选择器&#xff0c;它允许开发者根据元素的后代元素、兄弟元素或后续元素的存在或状态来选择目标元素。它本质上是一个“父选择器”或“关系选择器”&#xff0c;解决了 CSS 长期以来无法根据子元素反向选择父元素的痛点…

深度学习8(梯度下降算法改进2)

目录 RMSProp 算法 Adam算法 学习率衰减 RMSProp 算法 RMSProp(Root Mean Square Prop)算法是在对梯度进行指数加权平均的基础上&#xff0c;引入平方和平方根。 其中e是一个非常小的数&#xff0c;防止分母太小导致不稳定,当 dw 或 db 较大时&#xff0c;(du)2,(db)2会较大&…

JAVA面试宝典 -《网络编程核心:NIO 与 Netty 线程模型详解》

网络编程核心&#xff1a;NIO 与 Netty 线程模型详解 文章目录网络编程核心&#xff1a;NIO 与 Netty 线程模型详解一、传统 BIO 模型&#xff1a;排队买奶茶的阻塞模式 &#x1f964;1.1 专业解释1.2 简单点比喻1.3 简单示例二、NIO 模型&#xff1a;智能叫号餐厅系统 &#x…

蓝桥杯 第十六届(2025)真题思路复盘解析

本文以洛谷平台所提供的题目描述及评测数据为基础进行讲解。 前言&#xff1a;这是本人的蓝桥杯试卷&#xff0c;大概排省一前40%的位置&#xff0c;实际上这届题目偏难&#xff0c;我没有做出太多的有效得分。我把当时的思路和现在学习的思路都复盘进来&#xff0c;希望给大家…

兰顿蚂蚁路径lua测试

兰顿蚂蚁local p0 local x,y,z0,7,0 local function add() local result,id Block:getBlockID(x,y,z)if id1 thenBlock:destroyBlock(x,y,z,false) pp90 elseBlock:setBlockAll(x,y,z,1,0) pp-90 end x,zx-math.floor(0.5math.sin(math.rad(p))),z-math.floor(0.5math.cos(m…

【Axure RP】什么是Axure?Axure可以用来做什么?

【Axure RP】什么是Axure&#xff1f;Axure可以用来做什么&#xff1f; 目录【Axure RP】什么是Axure&#xff1f;Axure可以用来做什么&#xff1f;Axure RP简介Axure RP 是什么&#xff1f;Axure RP核心功能和应用场景Axure RP简介 Axure RP 是什么&#xff1f; Axure RP 是一…

Java项目:基于SSM框架实现的畅玩北海旅游网站管理系统【ssm+B/S架构+源码+数据库+毕业论文】

摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本畅玩北海旅游网站就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短时间内处理完毕庞大的数据信息…

NuxtJS中网络请求模块的封装与最佳实战

在网络开发中&#xff0c;封装一个简洁、高效的网络请求模块对于项目的可维护性和扩展性至关重要。本文将详细介绍如何在NuxtJS中封装一个通用的网络请求模块&#xff0c;并结合最佳实践来说明如何使用它来进行网络请求。良好的代码结构和封装&#xff0c;不但结构清晰还能够大…

云归子批量混剪软件批量剪辑软件批量分割视频更新记录

www.yunguizi.com 优化显卡硬件加速配置 ⚡ 优化 2025年07月07日 版本 v1.1.6 优化显卡硬件加速配置 修复了一些重要内容 &#x1f41b; 修复 2025年07月06日 版本 v1.1.6 修复了一些重要内容 重构读写机制 ⚡ 优化 2025年07月06日 版本 v1.1.6 优化了一些重要内容&#xff1b;…