首页 文章 精选 留言 我的

精选列表

搜索[编写],共10000篇文章
优秀的个人博客,低调大师

从零用Rust编写正反向代理,细说HTTP行为中的几种定时器

wmproxy wmproxy已用Rust实现http/https代理, socks5代理, 反向代理, 静态文件服务器,四层TCP/UDP转发,内网穿透,后续将实现websocket代理等,会将实现过程分享出来,感兴趣的可以一起造个轮子 项目地址 国内: https://gitee.com/tickbh/wmproxy github: https://github.com/tickbh/wmproxy 敏感的时间 现实生活中大家都对时间有着概念,比如“快上班了,要不然要迟到了。”、“这班怎么这么久,怎么还没下班?”、“啊?已经晚上12点啦,等我这把游戏玩完。”、“叮叮叮,起床闹钟一直在催着你起床了。” 闹钟、自然变化、生物钟为我们提供着时间的保证。而计算机的世界里,就靠着硬件定时器,控制着时间的流逝,如果哪一天本地时间和别人的时间不一致了,此时需要找别人对时,这也就是经典的网络时间协议(NTP)。 现实的生活中,通常以分钟或者小时乃至天去和别人约定时间,而在计算机的世界里,在我们看来那就是朝生暮死的蚍蜉一般,他们生命较短,所以对他们来说,通常用s或者ms来乃至μs做通知,所以需要严格的遵守时间约定,绝对不允许有赖床的行为。 HTTP行为中的定时器 HTTP/HTTPS/WebSocket的访问撑起了互联网总流量的半臂江山,日常接触中APP或者游戏这种对外服务的基本上均是通过HTTP及HTTPS进行服务,长链接由于兼容小程序这类的大部分游戏直接也从普通的Socket转为WebSocket直接做全网的兼容。WebSocket的基础协议是由HTTP升级而来,所以也归于HTTP协议。 主要有以下列行为定时器 连接超时定时器 读操作超时定时器 写操作超时定时器 读/写操作超时定时器(在规则的时间内同时完成读和写) keep-alive超时定时器(连接保持的最长时间) 定时器类的定义 相关的超时数据均存放在该类里,接下来类型进行相应的处理 #[derive(Debug)] pub struct TimeoutLayer { pub connect_timeout: Option<Duration>, pub read_timeout: Option<Duration>, pub write_timeout: Option<Duration>, pub timeout: Option<Duration>, /// keep alive 超时时长 pub ka_timeout: Option<Duration>, read_timeout_sleep: Option<Pin<Box<Sleep>>>, write_timeout_sleep: Option<Pin<Box<Sleep>>>, timeout_sleep: Option<Pin<Box<Sleep>>>, ka_timeout_sleep: Option<Pin<Box<Sleep>>>, } 连接超时定时器 此时约定的是客户端向服务端请求TCP连接建立的最长时间,如果没有约定,将由系统连接超时的或者确认不可达的时候才返回失败。 如果没有连接超时,那么以下我们的型业务场景模拟: 在弱网的环境下,比如手机信号不好的地方,一次连接请求建立可能会花费10秒左右才能返回,那么如果我们没有连接超时,用户在等待了8秒,客户端的界面都没有办法给出任何的响应,就会认为服务端出现了问题或者频繁的重启客户端应用不断的进行重试而得不到预期的反馈。在App设计中,对这种情况的用户体验极差,需要在指定的时间内给用户反馈出当前网络无法访问。 客户端的设计模型中,如果有定时请求或者埋点数据之类,如果没有超时机制,容易出现短时间内打开的socket过多出现资源耗尽的情况,其次客户端不知道是否将数据已经进行发送,不确认是否需要将该条数据进行缓存以便下一次推送。 在设计模型中,连接超时必不可少,因为各种业务场景的不同,需要要不同的时间内得到预期的反馈。以下是连接超时在Rust中的实现,因为只存在于客户端主动连接服务端,所以连接超时只在客户端实现。 async fn inner_connect<A: ToSocketAddrs>(&self, addr: A) -> ProtResult<TcpStream> { if self.inner.timeout.is_some() { // 获取是否配置了连接超时, 如果有连接超时那么指定timeout if let Some(connect) = &self.inner.timeout.as_ref().unwrap().connect_timeout { match tokio::time::timeout(*connect, TcpStream::connect(addr)).await { Ok(v) => { return Ok(v?) } Err(_) => return Err(ProtError::Extension("connect timeout")), } } } let tcp = TcpStream::connect(addr).await?; Ok(tcp) } 通过指定超时时间来对连接的建立监听。 读操作超时定时器 大部分HTTP请求,只有得到完整的数据才能进行处理,少部分如文件上传这种可以边上传边操作,而是否能开始操作关系到请求的响应时间。 读超时大概有以下的可能: 服务器处理请求的时间太长,导致客户端等待超时。 服务器返回的数据量过大,导致客户端读取数据的时间超过了规定的时间。 网络延迟或网络不稳定,导致客户端无法在规定的时间内读取完数据。 这造成客户端无法及时处理数据,可以报错好让客户端换备用线路或者备用服务器等以便及时的处理数据。 读操作我们不管服务端或者客户端,不管http/1.1或者http/2均由is_read_end字段来判定,在未读完当前请求的数据前,判断是否超时。 pub fn poll_ready( &mut self, cx: &mut Context<'_>, ready_time: Instant, is_read_end: bool, is_write_end: bool, is_idle: bool, ) -> ProtResult<()> { let now = Instant::now(); if !is_read_end { if let Some(read) = &self.read_timeout { let next = ready_time + *read; if now >= next { return Err(crate::ProtError::Extension("read timeout")); } if self.read_timeout_sleep.is_some() { self.read_timeout_sleep.as_mut().unwrap().as_mut().set(tokio::time::sleep_until(next.into())); } else { self.read_timeout_sleep = Some(Box::pin(tokio::time::sleep_until(next.into()))); } let _ = Pin::new(self.read_timeout_sleep.as_mut().unwrap()).poll(cx); } } Ok(()) } 其中比较复杂的是如何判断is_read_end,因为需要区分服务端客户端或者是http/1.1及http/2,这个源码实现 http2核心,http1.1核心 写操作超时定时器 对于客户端的写,就是将请求发送到服务端,而服务端的写,刚好是将返回发送给客户端。这是数据处理的重要的一环。 在异步的处理socket中,都会将socket设置成非阻塞,也就是nonblocking,此时我们会得到一个默认的内核缓冲区大小。如果在该缓冲区未满前,我们写入数据将是0等待,该缓冲区的数据将由系统进行数据发送给另一端。 如果对方不将我们的缓冲区数据读走,那么我们此时是无法在写入到该缓冲区的,如果远程端不读,我们的传输速度将会无限的接近于0KB/S。 此时如果是服务端,有数千上万个这种该连接,每分钟只读走几个字节的数据,那么没有写入操作,我们将要保持上万的空闲连接,而默认的端口连接数为65535,那么客户端将会耗尽我们的服务资源。此种为 <font color=green>[慢速攻击]</font>。 该操作是通过is_write_end来判断是否写入完成。监听方式和读的一致,核心代码在 timeout,此处不再赘述 读/写操作超时定时器 该定时器是由读和写需要共同来完成的,在很多场景中,我们只关心该请求需要耗时多少时间来完成,此时我们不关心是读的时间或者写的时间,所以此时表示请求完成的需要在这个时间下完成 就比如HTTP/1.1中的Slow headers,也就是慢速头攻击。正常来说,我们的http/1.1的头类似如下: GET / HTTP/1.1\r\n Host : wm-proxy.com\r\n Connection: keep-alive\r\n Keep-Alive: 900\r\n Content-Length: 100000000\r\n Content_Type: application/x-www-form-urlencoded\r\n Accept: *.*\r\n \r\n 整个报文的结束将有一个空白的\r\n,如果没有收到该标记,服务端无法得到完整的头信息,也无法正确的把数据转成Request,那么此时客户端可以占用了大量的连接,从而使服务端拒绝服务。 此定时器判断由is_read_end及is_write_end有一方为false,监听方法略。 keep-alive操作超时定时器 在http/1.1中,端口是可以复用的,从而减少socket的反复建立关闭,并可以一定程度上快速的响应,这是端口请求完成后,又没有后续的请求,此时当前socket线路为空闲,即当前空闲线路的保持时间。 keep-alive为保持连接,此参数用的好可以极大的加速服务的访问,此参数设置不好的时候,如设置成9999s,那么客户端将会保持当前的空闲socket很久,从而另一个程度上造成了拒绝服务了。 此判定由is_idle来判定,判断当前是否空闲,也就是上一个请求已经读写均已完成,后一个请求还未进来,此时就为空闲时间。监听方法雷同,略。 测试客户端 let url = "http://www.baidu.com"; let req = Request::builder().method("GET").header(HeaderName::ACCEPT_ENCODING, "gzip").url(url).body("").unwrap(); Instant::now()); let client = Client::builder() // 是否支持HTTP2 // .http2(false) // 是否仅使用HTTP2 .http2_only(true) // 连接使时时间3秒 .connect_timeout(Duration::new(5, 0)) // 设置keep-alive时间10秒 .ka_timeout(Duration::new(10, 0)) // 设置读超时5秒 // .read_timeout(Duration::new(5, 0)) // 设置写超时5秒 .write_timeout(Duration::new(5, 0)) .connect(url).await.unwrap(); //发起请求 let (mut recv, sender) = client.send2(req.into_type()).await?; //接收请求 let mut res = recv.recv().await.unwrap(); //接收所有body数据 res.body_mut().wait_all().await; 测试服务端 let mut server = Server::new(stream, Some(addr)); // 设置读操作5秒 server.set_read_timeout(Some(Duration::new(5, 0))); // 设置写超时5秒 server.set_write_timeout(Some(Duration::new(5, 0))); // 设置读写超时5秒 server.set_timeout(Some(Duration::new(5, 0))); async fn operate(req: Request<RecvStream>) -> ProtResult<Response<String>> { let response = Response::builder() .version(req.version().clone()) .body("Hello World\r\n".to_string())?; Ok(response) } let _ = server.incoming(operate).await; 结语 时间的尺度越小,那么对时间的敏感度越高,定时器是约束,也是保护,保护不受攻击。感谢定时器给我们构建一个更加稳定的互联网世界。 点击 <font color=green>[关注]</font>,<font color=green>[在看]</font>,<font color=green>[点赞]</font> 是对作者最大的支持

优秀的个人博客,低调大师

WPL/s v1.3.0发布 - 支持链接卡片 - 让你在 VS Code 中编写发布知乎专栏文章

WPL/s 是一个 VS Code 插件,允许你在 VS Code 中用 Markdown 写知乎文章。最新版支持知乎链接卡片。 链接卡片格式如下 [![zhihu-link-card:本项目 GitHub 主页](./pics/vs-code-extension-search-zhihu.png)](https://github.com/jks-liu/WPL-s) 语法上和一个图片链接一样,但图片的文字需要以zhihu-link-card:开头。知乎链接卡片的外观如下:

优秀的个人博客,低调大师

python自动化测试开发利器ulipad最佳实践(可写python测试代码也可编写selenium、Appium等)

介绍 UliPad是一个国人开发的python轻量级编辑器,导向和灵活的编程器。它如类浏览器,代码自动完成许多功能,如:HTML查看器,目录浏览器,向导等。 下载与安装 下载地址:https://pypi.python.org/pypi/UliPad 安装,傻瓜式,一路next即可 配置 安装好之后双击启动之后逐步进行下面的配置。 1、文件>目录浏览,这样我们可以在左侧看到目录方便管理脚本,最终效果图如下: 2、编辑>参数>python>设置python解释器>增加>选择你本地安装python的路径下的pythonw.exe,并把描述字段填上任意名字,保存即可,最终效果图如下: PS:我这里用的是python3哦 3、进入ulipad安装目录下的conf中,如果想配置python的模板可以修改template.python这个文件,比如我这里优化为了如下,这样你每次建立新的py文件时都可以显示了。 PS:模板里的注释暂时不支持中文,会有乱码 4、你还可以设置字体等格式,这个看个人需要了,很简单,如下图: 5、对于窗口的布局可以在菜单“窗口”中调整,这个自己试一下就明白啦 6、还可以安装一些插件,非常简单,按照下图操作即可,完全傻瓜式的 使用 点击新建文件图标下的python,就可以创建一个py文件了,然后输入代码内容,之后按F5即可运行,在下方的console中可以看到结果了,效果如下

优秀的个人博客,低调大师

项目实战_Python.编写一个高性能可扩展支持自定义的插件式监控系统?

项目简介: 说明: 主要用于集中化业务主动监控,支持任意自定义PY检测插件,适用于测试/正式环境业务联调检测,后端采用Python实现,具体实现代码请阅读代码. 项目思路: 项目结构: xmzoomeye-agent ├──app │├──conf ││├──default.ini ││├──__init__.py ││└──logging.ini │├──core ││├──__init__.py ││├──__init__.pyc ││├──main.py ││└──main.pyc │├──__init__.py │├──__init__.pyc │├──libs ││├──daemonize.py ││├──daemonize.pyc ││├──__init__.py ││├──__init__.pyc ││├──runutils.py ││└──runutils.pyc │├──plugins ││├──__init__.py ││├──__init__.pyc │└──tests │└──__init__.py ├──bin │├──__init__.py │├──restart_service.sh │├──start_service.sh │└──stop_service.sh ├──ChangeLog.txt ├──docs │├──default.ini │├──designidea ││├──mindmap.png ││└──notepad.txt │├──__init__.py │└──logging.ini ├──LICENSE.txt ├──logs │├──xmzoomeye-agent-error.log │├──xmzoomeye-agent-info.log │└──xmzoomeye-agent.pid ├──README ├──requirements.txt ├──restart_service.sh ├──setup.py ├──start_service.sh ├──stop_service.sh └──xmzoomeye-agent xmzoomeye-alert ├──app │├──conf ││├──default.ini ││├──__init__.py ││└──logging.ini │├──core ││├──__init__.py ││├──__init__.pyc ││├──main.py ││└──main.pyc │├──__init__.py │├──__init__.pyc │└──libs │├──alarm ││├──api.py ││├──__init__.py ││├──__init__.pyc ││├──mail.py ││├──sms.py ││└──weixin.py │├──daemonize.py │├──daemonize.pyc │├──__init__.py │├──__init__.pyc │├──runutils.py │└──runutils.pyc ├──bin │├──__init__.py │├──restart_service.sh │├──start_service.sh │└──stop_service.sh ├──ChangeLog.txt ├──docs │├──default.ini │├──designidea ││├──mindmap.png ││└──notepad.txt │├──__init__.py │└──logging.ini ├──LICENSE.txt ├──logs │├──xmzoomeye-alert-error.log │├──xmzoomeye-alert-info.log │└──xmzoomeye-alert.pid ├──README ├──requirements.txt ├──restart_service.sh ├──setup.py ├──start_service.sh ├──stop_service.sh └──xmzoomeye-alert 项目地址: xmzoomeye_agent: https://github.com/xmdevops/xmzoomeye_agent xmzoomeye_alert: xmzoomeye_alert: https://github.com/xmdevops/xmzoomeye_alert

优秀的个人博客,低调大师

从零用Rust编写正反向代理,一个数据包的神奇HTTP历险记!

wmproxy wmproxy已用Rust实现http/https代理, socks5代理, 反向代理, 静态文件服务器,四层TCP/UDP转发,内网穿透,后续将实现websocket代理等,会将实现过程分享出来,感兴趣的可以一起造个轮子 项目地址 国内: https://gitee.com/tickbh/wmproxy github: https://github.com/tickbh/wmproxy 数据包的自白 我是一个小小的数据包,今天我将跟着大部步出发,去体验传说中的HTTP之旅,听前辈说那是一场精彩绝伦的出走之旅。 旅行准备 首先,我先来到了出发地,他们在整理各项目数据,包括选择公交(HTTP1)还是自驾(HTTP2)或者询问是否有私家车(H2C),然后目的地是哪个房间(Path),是否防止旁边的人窥探(TLS),选择轻装上阵还是带上行李箱(GET或POST等),还有其它杂七杂八的事情(是否支持压缩,数据长度等)。 我问:“导游,我们什么时候可以出发”。 导游答:“别急,这躺路我熟的很,这次的数据有点重要,正在向对方获取加密信息,这是防止偷窥的秘诀。万一在中途被截走,那会使我们损失惨重。” 过了一会,我又问:“现在可以出发了吗?” 导游答:“可以了,我们通过交换已经将约定的加密信号确定下来了,让我先给你做个加工。” 我就跟着导游来到了一个加工场,进入其中,任由它来操作,当我走出加工场的时候,我突然发现我的模样完全跟变了个人似的。我差点认不出我自己。 我们就来到了公交站台(浏览器),他看到我们的到来,快速的帮我们排上了班次,紧接着,我们跟着车一直的往前走,我东看看西瞧瞧,我有看到像我一样乔装的自己都认不出来的,也看到了没有经过打扮的,都可以看的一清二楚,我猜那一定不怕别人窥探的吧(没用TLS)。 旅行中转 突然公交车停了下来,播报着:“欢迎来到wmproxy”。 我有点疑惑的问导游:“我记得我们的目的地不是这里,为什么在这里停下来?”。 身经百战的导游对我说:“看来我们的目的地被隐藏起来了,用来更好的保护目的地家园不被破坏,只有通过这里中转走专属的路线才能到达目的地。” 接着我急着问:“那我们在这里要做啥吖?” 导游回答:“接下来我们走的就是私人的领域了,我们路上看到的都是主人的朋友,并不会把我们的秘密泄漏出去,所以我们需要把我们身上打扮的乱七八糟的还原。” 我就跟随着来到了加工场,加工场把我们身上乱七八糟的装扮通过特定的方法进行了还原(卸掉TLS转HTTP),走出加工场,我又看到帅气的自己。我问:“那么接下来我们做什么?” 导游回答:“根据我们原来的信息,他现在要安排我们做私家车(HTTP2),好灵活地做响应,你看,那车已经来了,我们一起上车吧。” 我们坐上了私家车,我发现我带的东西被切割成了奇奇怪怪的几个部分。我就问司机:“为什么原来我就一个整体,现在变成了奇怪的几个部分?” 司机笑着回答:“在这车里,通常副驾驶上坐着Header,也就是你带着的那些属性全都组装在这里了,后排通常就是额外的数据包,当然你们数据包兄弟可能会很多,你看看你的手臂上,跟着相同导游的此刻都被挂上了红色的布。” 我才发现,原来刚在加工场的时候还帮我和导游都做上了特殊的标记了吖,而且我还发现,每个人头上还顶着一个特殊的帽子。包括了颜色,还有一串特殊的数字。看起来附带了我身高体重(实际长度)这些信息。 旅行到达 私家车停在了一个漂亮的房间前面,我想这是旅程的目地吧。 此时我终于知道我这躺的任务了,原来我需要来这里获得一个重要的文件,这文件数据量还大的有点夸张,是我来时数据的上万倍(Content-Length)。 这时候我有点慌乱的找到导游:“这要带的数据那么多,那么重要,我怎么样才能把他们安全的带回去吖。” 导游这时候就说:“你还记得我们开始带的工具包列表(Accept-Encoding)吗?” 我说:“记得记得,当时好像把名字记下来了,好像是说家里有真空机(gzip),压缩机(brotli)吧?” 导游答:“对的对的,你看到那边的那座大山(gzip)吧,等下我们会带着数据兄弟们爬上那大山,到时候我们就可以瘦很多,那样子接下来我们动用的资源会小很多。” 我们带着浩浩荡荡的数据大军去爬了山,我确实发现我们的个头都小了许多,但是我觉得这大军的数量远远没有一开始说的上万倍。 我问:“这大军的数量不对吖,不会有兄弟们迷路了吧?” 导游笑着回答:“这边的房子就这么大,如果把数据一下子从异次元全部召唤出来(文件中读取)那不直接把这小小的房子全部挤满了吖,看到上面那个指示牌了没有?” 只见指示牌上面写着:“当前房间可容纳人数4096/4096”,此时前面有100个兄弟走出了房间就变成了,3996/4096,然后又看到异次元召唤出了新的100个兄弟。 此时我晃然大悟:“原来这东西就是控制着不会膨胀的秘密吖(内存缓冲区已满)。” 旅行返程 当我们瘦完身后,就有一辆辆的小汽车来接我们回家了 此时一辆辆汽车大军稳稳的向前行驶,突然间速度慢了下来,我就很好奇的问司机:“刚刚不是速度很快的吗,怎么到这个地方突然间速度就慢下来了吖?” 司机指了指前面说:“前面是一段较窄的路,你看看两边的车流,如果全速全进的话,大家都会堵死在这段路上,所以你看上方,有个牌子100辆/分钟,也就是一分钟只能通过100辆,要不然就会挤到前面的窄路上,所以我们现在速度是慢了下来,但是我们这条线路还是可以每分钟可以通过100辆,也不算慢。” 于是我就往两边看,两边的车也都是差不多的速度在通行,慢慢的我们来到了比较狭窄的路,确实这里无法通行通行太多的车(从内网转入公网,传输能力下降),我想:“高负载的情况下确实只能通过这种方式来限制,要不然此刻交通应该瘫痪掉了吧,大家越急着挤,越没法正常通行。” 紧接着,我们又回到了中转站了,我突然很好奇的想着:“要是我们兄弟全部挤到中转站这里,他会不会直接被挤满了?” 这时我听到导游说:“别发呆了,公交车来了,我们该出发了。” 我顿时有点迷惑:“我们后面不是还有很多兄弟吗?不用等他们集合完再出发吗?” 导游就笑着说:“如果全部集合在出发,那我们就得停下来等,然后启动的时候后面的兄弟又得等前面的走完才能走,这样子速度就慢了很多,这是其一。另外,你看这中转台上也容不下这么多的兄弟同时停留在这里,他根据我们帽子的颜色帮我们分好了公交车啦,上车!”(此时代理只处理了头部数据,body数据只做简单的转发) 我突然想到我们现在来到了公共区域,我问导游:“我们是不是得保证我们的数据安全,现在我们都是属于公共区域了。” 导游回过神来说,对对我们先去加工厂处理下,那个是我们的专属加工场。还好你提醒,要不然数据就不安全了。(TLS加密) 我们从加工厂出来乘上公交车,一路平稳的来到了出发的站台(浏览器),这时候我们一个个从加厂场出来(TLS解密),我们的兄弟有点多,浏览器的站台有点放不下了,我就问:“我们不是到达了目的地了吗?他怎么不还来接我们到目的地?” 导游笑着说:“此次我们带回来的信息量有点大,而且还是经过了瘦身的,我们等下去那个标gzip的房间进行处理,然后你看那边有个异次元空间(临时文件),我们先到那里下,好让后来的兄弟有地方住。” 我跟着来到了异次元空间,里面是一个空旷,超大的空间,我们这么多兄弟秩序井然的排列在一起,直到最后一个兄弟到达,我们就看到了前面有一个出口,我就问:“从那个出口出去我们就完成任务了吗?” 导游就回答:“从那个出口,不要乱,现在兄弟都到了,知道大家各自的位置,就不会乱套了,大家排队往前走,不要乱。” 当我们一个个出来后,慢慢的把身子还原回来,我看着自己变成了一个巨大的人,很完整的,帅气的,我想我应该完成了这一项任务了吧。 此时浏览器播报,数据传输完成,完整无误,任务完成,进行展示。 结语 这是数据的一趟历险记,也是互联网上每天都在发生的,他快速稳定的传播,给我们构建了一个美好的世界。 点击 <font color=green>[关注]</font>,<font color=green>[在看]</font>,<font color=green>[点赞]</font> 是对作者最大的支持

优秀的个人博客,低调大师

一款让你系统支持热更新,编排,脚本编写逻辑的国产规则引擎框架

前言 上海的天气降温让人猝不及防,但是我们的迭代速度却井然有序。 今天我们带来了LiteFlow v2.9.4版本。 我们每次的发布的issue有很大一部分依托于我们的使用者社区,社区人越来越多。我看到了使用者在使用过程中遇到的问题,也收集了很多使用过程中很有意思的建议。这些也正是我们每一次迭代的方向。谢谢那么多的小伙伴的支持和建议,LiteFlow一直会是一个以社区为驱动的开源框架。 LiteFlow是一个开源编排式规则引擎,能够让你的系统逻辑任意编排,使用脚本书写逻辑,所有的逻辑和规则均可热变更。设计系统和重构系统的神器。 如果你是第一次知道这个项目,可以去官网或相关的主页进行了解: 项目官网: https://liteflow.yomahub.com gitee托管仓库: https://gitee.com/dromara/liteFlow github托管仓库: https://github.com/dromara/liteflow v2.9.4介绍 新版本我们依旧依托于社区,一共完成了14个issue。 其中80%的issue来自于社区使用者。 2.9.4版本完全兼容2.9.3版本,可以无缝升级。 新的脚本引擎 鉴于之前社区有人反应LiteFlow提供的Javascript脚本引擎是基于jdk的,而JDK的Javascript引擎只支持到ES5规范,且不支持Java 17。 所以这次我们新增了一个Javascript引擎:GraalJs。支持ES6规范,且支持Java 8~17。 当然老的引擎我们还是保留,如果是简单的js语法,你依旧可以用老的引擎。 关于这块详情请参考官网的选择脚本语言章节。 提供规则验证接口 虽然LiteFlow在启动时会去编译所有的规则,如果有错也会详细报出,但是在更改脚本前,使用者可能不太确信自己的规则写的有没有问题。所以在社区内,有人提出了希望增加一个验证规则的接口。 那这次我们也提供了相应的接口。详情请参考官网的验证规则章节。 Zk和Etcd支持局部刷新机制 如果你使用zk或者Etcd,你在zk和etcd里更改了规则,会自动推送到相应的应用进行无感自动刷新。 但是之前的实现模式是全部刷新,即不管你改了哪个规则,所有的规则刷新一遍。虽然LiteFlow刷新速度非常快速,但是这种实现模式还是不够优雅。 这次我们实现了局部刷新,即你改变哪个即刷新哪个。 声明式组件的二次动态代理问题 在社区内,我们也收到了许多使用声明式组件特性小伙伴们的反馈,在声明式组件上使用类似事务标注等需要动态代理的特性时,LiteFlow的声明式组件会报错。 经过核验,我们发现LiteFlow之前漏考虑了二次动态代理的问题,这次我们修复了。 其他修复 在新版本中,我们修复其他issue也有很多,包括脚本对元数据取值的bug,@ScriptBean标注所带来的一些小问题,脚本异常处理的优化等等。 完整更新列表 特性#I61XYZ额外提供GraalJs引擎,在js上多一个选择 https://gitee.com/dromara/liteFlow/issues/I61XYZ 增强#I63C31zk,etcd支持只刷新改变的部分 https://gitee.com/dromara/liteFlow/issues/I63C31 增强#I61EMZ增加一个验证EL规则的api,供检查之用 https://gitee.com/dromara/liteFlow/issues/I61EMZ 增强#I633VH建议FlowBus提供批量移除子链方法 https://gitee.com/dromara/liteFlow/issues/I633VH 增强#I61RI0希望可以开放对QLExpress的一些操作! https://gitee.com/dromara/liteFlow/issues/I61RI0 增强#I622I9内部代码规范ChainName和ChainId问题 https://gitee.com/dromara/liteFlow/issues/I622I9 增强#I61LYN规范问题和不必要的import常量提取等 https://gitee.com/dromara/liteFlow/issues/I61LYN 修复#I62PV3声明式组件如果把LiteflowMethod定义在父类中,不执行 https://gitee.com/dromara/liteFlow/issues/I62PV3 修复#I62DT1如果对上下文标注@ScriptBean,那么脚本和java中拿到的上下文并不是同一个上下文 https://gitee.com/dromara/liteFlow/issues/I62DT1 修复#I61H49脚本异常希望可以抛出到response https://gitee.com/dromara/liteFlow/issues/I61H49 修复#I631ZFgroovy脚本接入时,自定义异常抛出后被组件失败异常覆盖 https://gitee.com/dromara/liteFlow/issues/I631ZF 修复#I61HIO方法级的组件声明,然后在方法上打Spring的事务注解@Transactional,会报错 https://gitee.com/dromara/liteFlow/issues/I61HIO 修复#I62CB8脚本与java交互取元数据的问题 https://gitee.com/dromara/liteFlow/issues/I62CB8 修复#I61UZ6switch选择组件使用标签在同一组件时固定选到最后一个 https://gitee.com/dromara/liteFlow/issues/I61UZ6 社区 LiteFlow的社区是一个异常活跃的开源社区,这里有许多的开源大佬,技术大牛,群内的小伙伴也很乐意帮你去回答问题。 如果你在使用和学习中有任何问题,可以通过以下官网或者以下方式进入社区群。 https://liteflow.yomahub.com/pages/73c2c3/

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册