-
前言在数字化时代,Web应用的安全性成为了不可忽视的重要环节。随着网络攻击手段的不断演进,跨站请求伪造(CSRF)和用户追踪成为了网络安全的两大威胁。为了更有效地保护用户数据,Chrome 51及后续版本引入了SameSite Cookie属性,这是一个旨在增强Web应用安全性的重要特性。本文将深入探讨SameSite Cookie的三种设置类型及其工作原理,帮助开发者更好地理解并应用这一安全特性。SameSite Cookie属性简介SameSite Cookie属性是一个HTTP响应头部字段,用于指定浏览器是否应该允许跨站请求携带Cookie。这一特性通过限制Cookie的发送范围,有效降低了CSRF攻击的风险,并有助于阻止第三方恶意追踪用户行为。SameSite Cookie的三种类型SameSite=None行为描述:当Cookie的SameSite属性设置为None时,该Cookie将在所有跨源请求中发送,其行为类似于没有设置SameSite属性的旧版Cookie。然而,值得注意的是,如果设置了SameSite=None,还必须同时设置Secure属性(即Cookie必须通过HTTPS传输),否则浏览器将忽略SameSite属性,按照旧版行为处理。使用场景:适用于那些确实需要在跨站请求中传递Cookie的场景,如API调用、OAuth认证流程等。SameSite=Lax行为描述:设置为Lax的Cookie将仅在安全的顶级导航上下文(如用户点击链接或提交表单导致的页面跳转)中发送,且这些请求必须是GET请求。对于POST请求、iframe加载、AJAX调用等跨站请求,浏览器将不会发送这些Cookie。使用场景:适用于大多数Web应用,因为它既保证了跨站请求的安全性,又保留了用户在浏览时正常的Cookie传递需求。SameSite=Strict行为描述:设置为Strict的Cookie仅在完全同源的请求中发送,即用户直接在浏览器地址栏中输入网址或通过书签访问网站时。对于任何形式的跨站请求,包括第三方链接、图片加载等,浏览器都不会发送这些Cookie。使用场景:适用于对安全性要求极高的场景,如银行、金融等敏感领域的应用。通过严格限制Cookie的发送,可以最大程度地减少CSRF攻击的风险。开发者应如何应用评估需求:首先,开发者需要评估自己的Web应用是否需要跨站请求传递Cookie。如果不需要,建议将Cookie的SameSite属性设置为Strict。修改服务器配置:在服务器响应中设置Cookie的SameSite属性。这通常需要在HTTP响应头部中添加Set-Cookie字段,并指定SameSite的值。测试与验证:在更改配置后,进行全面的测试以确保应用的功能和安全性不受影响。特别是要注意检查那些依赖跨站请求传递Cookie的功能是否仍然正常工作。关注兼容性:虽然SameSite Cookie属性在主流浏览器中得到了广泛支持,但仍有部分旧版浏览器可能不支持这一特性。因此,开发者需要关注浏览器的兼容性问题,并考虑采取适当的回退措施。结语SameSite Cookie属性的引入是Web安全领域的一项重要进步,它为我们提供了一种简单而有效的方式来减少CSRF攻击的风险并保护用户隐私。作为开发者,我们应该积极学习和应用这一特性,为我们的Web应用筑起一道坚固的安全防线。
-
在数字化时代,用户体验(UX)和可访问性(Accessibility)成为了网站设计中不可或缺的一部分。随着设备和技术的发展,用户对于个性化体验的需求日益增长,其中之一就是根据用户的偏好自动调整网站的主题颜色。幸运的是,CSS Media Queries 提供了一个强大的特性——prefers-color-scheme,它允许网站根据用户的系统颜色偏好(深色模式或浅色模式)自动切换主题。什么是 prefers-color-scheme?prefers-color-scheme 是一个 CSS 媒体查询特性,它允许网页根据用户的系统颜色偏好(深色模式或浅色模式)来应用不同的样式。这一特性极大地提升了用户体验,因为它允许网站自动适应用户的视觉偏好,无需用户手动切换主题。如何使用 prefers-color-scheme?基本语法prefers-color-scheme 可以与 CSS 的 @media 规则一起使用,来定义在不同颜色偏好下的样式。其基本语法如下:@media (prefers-color-scheme: dark) { /* 深色模式下的样式 */ body { background-color: #333; color: #fff; } } @media (prefers-color-scheme: light) { /* 浅色模式下的样式 */ body { background-color: #fff; color: #333; } } /* 如果没有指定偏好,可以设置一个默认样式 */ body { background-color: #fff; /* 默认浅色模式 */ color: #333; }实际应用在实际应用中,prefers-color-scheme 可以用来改变整个网站的主题,包括背景色、文字颜色、链接颜色、按钮样式等。以下是一个简单的示例,展示了如何为深色和浅色模式设置不同的按钮样式:/* 深色模式按钮 */ @media (prefers-color-scheme: dark) { .button { background-color: #4CAF50; /* 绿色 */ color: #000; border: 1px solid #333; } } /* 浅色模式按钮 */ @media (prefers-color-scheme: light) { .button { background-color: #f44336; /* 红色 */ color: #fff; border: 1px solid #ddd; } } /* 通用样式 */ .button { padding: 10px 20px; text-align: center; text-decoration: none; display: inline-block; font-size: 16px; margin: 4px 2px; cursor: pointer; border-radius: 5px; }注意事项兼容性:虽然大多数现代浏览器都支持 prefers-color-scheme,但在一些旧版浏览器上可能无法正常工作。因此,建议为不支持此特性的浏览器设置一个合理的默认样式。性能考虑:虽然 prefers-color-scheme 的使用对性能影响微乎其微,但在设计网站时仍需考虑整体性能优化。用户控制:虽然 prefers-color-scheme 提供了自动切换主题的能力,但最好也提供用户手动切换主题的功能,以满足用户的个性化需求。结论prefers-color-scheme 是一个强大的 CSS 特性,它允许网站根据用户的系统颜色偏好自动切换主题,从而提升用户体验和可访问性。通过合理使用这一特性,我们可以创建更加智能、更加人性化的网站,让用户在浏览时感到更加舒适和自在。
-
在JavaScript中,判断一个元素是否无法滚动(即已经滚动到顶部或底部),可以通过检查该元素的scrollTop属性与scrollHeight和clientHeight之间的关系来实现。scrollTop表示元素内部被卷上去的高度,scrollHeight是元素内容的总高度(包括不可见部分),而clientHeight是元素内部的高度,包括padding但不包括border、margin、horizontal scrollbar(如果存在的话)、或::before/::after伪元素的高度。判断元素是否滚动到顶部如果元素已经滚动到顶部,那么scrollTop的值应该为0(或者非常接近0,考虑到可能的浮点数精度问题)。function isScrolledToTop(element) { return element.scrollTop === 0; }判断元素是否滚动到底部要判断元素是否滚动到底部,可以比较scrollTop加上clientHeight是否等于或大于scrollHeight。function isScrolledToBottom(element) { return element.scrollTop + element.clientHeight >= element.scrollHeight; }示例以下是一个简单的示例,展示了如何在一个可滚动的div元素上应用这些函数:HTML:<div id="scrollableDiv" style="height: 200px; overflow-y: auto;"> <!-- 足够的内容以使其可滚动 --> <div style="height: 1000px;">滚动内容...</div> </div> <button onclick="checkScroll()">检查滚动位置</button>JavaScript:function checkScroll() { var scrollableDiv = document.getElementById('scrollableDiv'); if (isScrolledToTop(scrollableDiv)) { console.log('已经滚动到顶部'); } else if (isScrolledToBottom(scrollableDiv)) { console.log('已经滚动到底部'); } else { console.log('在中间位置'); } } function isScrolledToTop(element) { return element.scrollTop === 0; } function isScrolledToBottom(element) { return element.scrollTop + element.clientHeight >= element.scrollHeight; }在这个示例中,我们有一个可滚动的div元素,并添加了一个按钮来检查该元素当前的滚动位置。点击按钮时,会调用checkScroll函数,该函数使用isScrolledToTop和isScrolledToBottom函数来判断元素是否滚动到了顶部或底部,并打印相应的消息到控制台。
-
在JavaScript中,没有原生的“滚动结束”事件可以直接监听。不过,你可以通过监听滚动事件(scroll)并使用一些技术来模拟一个“滚动结束”或“滚动停止”的行为。这种方法通常涉及到设置一个定时器(setTimeout 或 requestAnimationFrame),当滚动事件触发时重置定时器,定时器到时(即用户停止滚动一段时间后)则认为滚动结束。以下是一个使用setTimeout来实现“滚动结束”事件的示例:let scrollTimeout; // 监听滚动事件 window.addEventListener('scroll', function() { // 如果已经设置了定时器,则清除它 if (scrollTimeout) { clearTimeout(scrollTimeout); } // 设置一个新的定时器,等待一段时间(例如50毫秒)来检测是否停止滚动 scrollTimeout = setTimeout(function() { // 在这里执行你希望在滚动结束时执行的代码 console.log('滚动结束了!'); // 注意:此时你可以放心地更新页面布局或执行重绘等操作 // 清除定时器,尽管在这个场景中不是必须的,因为我们已经执行了回调函数 // 但如果在回调函数中需要重置某些状态,确保不会重复触发,这个清除是有用的 clearTimeout(scrollTimeout); scrollTimeout = null; }, 50); // 可以调整这个值以适应不同的滚动速度或延迟需求 });这个方法的一个好处是它可以适应不同用户的滚动速度。不过,如果你发现即使停止滚动后仍然频繁触发“滚动结束”的逻辑,你可能需要增加延迟时间(即setTimeout中的时间)。此外,还有一个使用requestAnimationFrame的方法,这种方法可能更加精确,尤其是在需要精确控制动画或重绘的时机时。不过,由于requestAnimationFrame设计之初是为了动画而不是检测滚动停止,所以上述的setTimeout方法对于大多数“滚动结束”事件的模拟已经足够好用了。请记得,在用户快速滚动时,这些方法可能不会按预期工作,因为滚动事件可能会在定时器到时之前连续触发,从而重置定时器。但通常情况下,对于用户体验而言,这种方法已经足够好了。
-
在JavaScript中,不同的存储机制对应着不同的函数或API。以下是您提到的存储机制及其对应的JavaScript函数或API:Cookie:设置Cookie:document.cookie = "username=John Doe; expires=Thu, 18 Dec 2023 12:00:00 UTC; path=/";读取Cookie:通过访问document.cookie属性。会话存储(SessionStorage):设置会话存储项:sessionStorage.setItem('key', 'value');读取会话存储项:var value = sessionStorage.getItem('key');Indexed DB:Indexed DB是一个复杂的API,不直接对应一个简单的函数。你需要通过一系列步骤来打开数据库、创建对象仓库、进行事务处理以及读写数据。打开数据库:var request = indexedDB.open("MyDatabase", 1);在成功回调中,你可以创建对象仓库、读写数据等。本地存储(LocalStorage):设置本地存储项:localStorage.setItem('key', 'value');读取本地存储项:var value = localStorage.getItem('key');缓存存储(Cache API):缓存存储主要通过caches对象来访问,它提供了多个方法用于管理缓存,如open、match、add、addAll、put、delete等。打开缓存:caches.open('my-cache-name').then(function(cache) { /* 使用cache对象 */ });添加请求到缓存:cache.add(request).then(function() { /* 添加成功 */ });每种存储机制都有其特定的用途和限制,选择哪种取决于你的具体需求,如数据量、持久性、浏览器兼容性等。
-
缓存存储和本地存储是Web开发中常用的两种数据存储方式,它们在多个方面存在区别。以下是对这两种存储方式的详细比较:缓存存储定义与功能:缓存存储是一种临时性的数据存储方式,用于提高网页加载速度。它通过将数据存储在内存或磁盘中,当用户再次访问相同的资源时,浏览器会优先从缓存中读取数据,而不是从服务器重新请求。特点:临时性:缓存的数据通常是临时的,可以在浏览器关闭后自动清除,或者根据HTTP头部信息设置的过期时间来清除。自动管理:缓存的管理大多由浏览器自动完成,用户通常不需要手动干预。性能优化:缓存的主要目的是减少网络请求,提高页面加载速度,优化用户体验。本地存储本地存储通常指的是HTML5 Web Storage API中的localStorage和sessionStorage,以及IndexedDB等存储机制。定义与功能:本地存储是一种持久化的数据存储方式,数据存储在浏览器端,不会随页面刷新或浏览器关闭而消失。它允许网站在用户的浏览器中存储数据,以便在用户重新访问网站时能够恢复之前的状态或数据。特点:持久性:本地存储的数据会长期保存在浏览器中,直到被手动清除或浏览器清除缓存。存储容量:相比cookie,本地存储提供了更大的存储容量(如localStorage和sessionStorage通常提供5MB的存储空间,而IndexedDB的存储空间则更大)。数据安全:本地存储的数据仅在用户的浏览器中可用,不会发送到服务器,除非网站代码显式地这样做。灵活性:本地存储支持存储多种类型的数据,包括字符串、对象等(对于非字符串类型的数据,通常需要使用JSON进行序列化)。缓存存储与本地存储的区别缓存存储本地存储定义与功能临时性数据存储,用于提高网页加载速度持久化数据存储,用于在浏览器中保存数据存储位置内存或磁盘浏览器端(localStorage和sessionStorage在浏览器本地存储,IndexedDB在浏览器数据库中)数据持久性临时性,可自动清除或根据过期时间清除持久性,直到被手动清除或浏览器清除缓存存储容量取决于浏览器和缓存策略较大(如localStorage和sessionStorage通常5MB,IndexedDB更大)数据安全性较低(数据可能被清除)较高(数据仅在用户浏览器中,除非显式发送)应用场景提高页面加载速度,减少网络请求在浏览器中保存用户状态、偏好设置等需要持久保存的数据综上所述,缓存存储和本地存储在定义、功能、存储位置、数据持久性、存储容量、数据安全性和应用场景等方面存在明显的区别。开发人员应根据具体需求选择合适的存储方式。
-
大家好,6月份干货合集又来了,本次带来的内容涵盖了,java,Android,html,git,mysql,linux,网络协议,Jenkins等诸多内容供您选择 1.模拟买票小练习-线程资源同步小练习-synchronized使用 https://bbs.huaweicloud.com/forum/thread-02109154511981591054-1-1.html 2.Android Intent-Filter匹配规则解析 https://bbs.huaweicloud.com/forum/thread-02109154511945084053-1-1.html 3.web前端入门面对的git、angular和web开发必备的技术以及前端开发如何的运用技术? https://bbs.huaweicloud.com/forum/thread-02109154511910212052-1-1.html 4.前端技术分享(html总结) https://bbs.huaweicloud.com/forum/thread-02109154511861684051-1-1.html 5.0基础小白如何玩转前端开发? https://bbs.huaweicloud.com/forum/thread-02109154466914607049-1-1.html 6.RTSP 和 RTMP通过ffmpeg实现将本地摄像头推流到RTSP服务器-转载 https://bbs.huaweicloud.com/forum/thread-0244153476749248016-1-1.html 7.mysql8.0 性能优化配置 innodb_buffer_pool_size-转载 https://bbs.huaweicloud.com/forum/thread-02109153476715536012-1-1.html 8.linux 服务器无 sudo 权限非 root 用户安装特定版本 cuda -转载 https://bbs.huaweicloud.com/forum/thread-0224153476680638017-1-1.html 9.网络网络层之(6)ICMPv4协议-转载 https://bbs.huaweicloud.com/forum/thread-0273153476617308017-1-1.html 10.Window下SRS服务器的搭建-转载 https://bbs.huaweicloud.com/forum/thread-0264153476579428008-1-1.html 11.探索SRS-GB28181:一款强大的国标GB28181视频服务器-转载 https://bbs.huaweicloud.com/forum/thread-0210153476525852014-1-1.html 12.容器化部署 Jenkins,并配置SSH远程操作服务器-转载 https://bbs.huaweicloud.com/forum/thread-0224153476500551016-1-1.html 13.如何查看ubuntu服务器上防火墙信息-转载 https://bbs.huaweicloud.com/forum/thread-02127153476446295011-1-1.html 14.探索GoServer:高效、易用的Golang服务器框架 -转载 https://bbs.huaweicloud.com/forum/thread-0210153476421991013-1-1.html 15.使用Linux命令修改服务器时间及设置时区-转载 https://bbs.huaweicloud.com/forum/thread-0273153476396290016-1-1.html 16.pg_rman在恢复服务器上恢复源库的备份-转载 https://bbs.huaweicloud.com/forum/thread-0244153476353118015-1-1.html 17.linux之用户和权限-转载 https://bbs.huaweicloud.com/forum/thread-0273153476326497015-1-1.html 18.Linux-查看服务器--硬件配置信息-转载 https://bbs.huaweicloud.com/forum/thread-0273153476291979014-1-1.html 19.Python如何对文件进行重命名操作?-转载
-
前言在前端开发中,我们经常需要遍历 DOM 树来查找特定的元素。虽然 querySelector 和 querySelectorAll 是非常强大的工具,但在某些情况下,我们可能只关心当前元素或其祖先元素中最近的一个满足特定条件的元素。这时,JavaScript 的 Element.closest() 方法就派上了用场。closest() 方法是什么closest() 方法返回调用它的元素本身或其最近的祖先元素(包括父元素),该元素匹配给定的选择器字符串。如果没有找到匹配的元素,则返回 null。如何使用 closest()使用 closest() 方法的基本语法如下:element.closest(selectorString);element:你想要开始搜索的 DOM 元素。selectorString:一个 CSS 选择器字符串,用于匹配你想要找到的元素。示例假设我们有以下的 HTML 结构:<div class="container"> <div class="item"> <button id="myButton">点击我</button> </div> <div class="item"> <!-- 其他内容 --> </div> </div>如果我们想要从 myButton 按钮开始,找到最近的带有 container 类的祖先元素,我们可以这样做:document.getElementById('myButton').addEventListener('click', function() { var container = this.closest('.container'); if (container) { console.log('找到了容器元素:', container); } else { console.log('没有找到匹配的容器元素'); } });在这个例子中,当用户点击按钮时,会触发一个事件监听器。该监听器使用 closest() 方法来查找最近的带有 container 类的祖先元素。如果找到了这样的元素,它就会被存储在 container 变量中,并在控制台中打印出来。如果没有找到匹配的元素,则会打印出相应的消息。注意事项closest() 方法从当前元素开始向上搜索 DOM 树,直到找到匹配的元素或到达根元素(通常是 <html> 元素)。如果当前元素本身匹配给定的选择器,那么 closest() 将返回当前元素。如果给定的选择器无效或无法解析,closest() 将抛出一个 SyntaxError。不同于 querySelector() 和 querySelectorAll(),closest() 只返回第一个匹配的元素(如果有的话),而不是一个包含所有匹配元素的 NodeList。总结closest() 方法是 JavaScript 中一个非常有用的工具,它允许我们轻松地找到当前元素或其最近的祖先元素中匹配特定选择器的元素。无论你是在处理事件处理程序、构建复杂的 UI 组件,还是进行任何需要遍历 DOM 树的操作时,它都可以为你节省大量的时间和代码。
-
大家好,本次带来的是5月份技术合集,其中包含了JavaScript,java,python,golang,openflow,linux供大家学习交流。 1.正则表达式常见密码验证方式总结大全【转】 https://bbs.huaweicloud.com/forum/thread-0235152528388647043-1-1.html 2.正则表达式中的$分组使用示例详解【转】 https://bbs.huaweicloud.com/forum/thread-0220152528348235034-1-1.html 3.正则表达式匹配双引号常用例子总结【转】 https://bbs.huaweicloud.com/forum/thread-02105152528298749035-1-1.html 4.python和JavaScript的正则表达式详细使用对比【转】 https://bbs.huaweicloud.com/forum/thread-0220152524278914033-1-1.html 5.日期校验 / 时间校验正则表达式深入解析(超实用!)【转】 https://bbs.huaweicloud.com/forum/thread-0297152524193613042-1-1.html 6.Python使用xpath对解析内容进行数据提取【转】 https://bbs.huaweicloud.com/forum/thread-02105152523702186034-1-1.html 7.基于Go实现TCP长连接上的请求数控制【转】 https://bbs.huaweicloud.com/forum/thread-0249152523497606033-1-1.html 8.Golang使用原生http实现中间件的代码详解【转】 https://bbs.huaweicloud.com/forum/thread-0297152523442936041-1-1.html 9.Python中GPU计算的库pycuda的使用【转】 https://bbs.huaweicloud.com/forum/thread-0297152523272604040-1-1.html 10.python打印exception信息的方法【转】 https://bbs.huaweicloud.com/forum/thread-0297152522000640037-1-1.html 11.详解如何利用Python代码删除Word文档空白行【转】 https://bbs.huaweicloud.com/forum/thread-0220152518833622030-1-1.html 12.使用Python和大模型进行数据分析和文本生成【转】 https://bbs.huaweicloud.com/forum/thread-0266152521305596026-1-1.html 13.使用Python进行数据清洗和预处理的实现代码【转】 https://bbs.huaweicloud.com/forum/thread-02127152520239578032-1-1.html 14.使用Python进行物联网设备的控制与数据收集【转】 https://bbs.huaweicloud.com/forum/thread-0235152519161548040-1-1.html 15.利用Python自动化识别与删除Excel表格空白行和列【转】 https://bbs.huaweicloud.com/forum/thread-0249152519105690032-1-1.html 16.通用数据模型 https://bbs.huaweicloud.com/forum/thread-02127152343988086023-1-1.html 17.容器网络 https://bbs.huaweicloud.com/forum/thread-0219152343799742022-1-1.html 18.BFD for openflow https://bbs.huaweicloud.com/forum/thread-02127152343656881022-1-1.html 19.Linux systemd 定时任务 https://bbs.huaweicloud.com/forum/thread-0235152250634012021-1-1.html 20.Linux启动过程以及7种运行级别 https://bbs.huaweicloud.com/forum/thread-0266152250544314007-1-1.html
-
1.1 至少1个大写字母(?=.*?[A-Z])1.2 至少1个小写英文字母(?=.*?[a-z])1.2 至少1位数字(?=.*?[0-9])1.2 至少有1个特殊字符(?=.?[#?!@$%^&-])1.3 最小8个长度{8,}二、常见密码正则表达式2.1 至少8-16个字符,至少1个大写字母,1个小写字母和1个数字,其他可以是任意字符/(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[]{8,16}$//^(?=.[a-z])(?=.[A-Z])(?=.*\d)[\s\S]{8,16}$/2.2 至少8个字符,至少1个大写字母,1个小写字母和1个数字,不能包含特殊字符(非数字字母)^(?=.[A-Za-z])(?=.\d)[A-Za-z\d]{8,}$2.3 至少8个字符,至少1个字母,1个数字和1个特殊字符^(?=.[A-Za-z])(?=.\d)(?=.[ @ @ @!%#?&])[A-Za-z\d @ @ @!%*#?&]{8,}$2.4 至少8个字符,至少1个大写字母,1个小写字母和1个数字^(?=.[a-z])(?=.[A-Z])(?=.*\d)[a-zA-Z\d]{8,}$2.5 至少8个字符,至少1个大写字母,1个小写字母,1个数字和1个特殊字符^(?=.[a-z])(?=.[A-Z])(?=.\d)(?=.[ @ @ @!%?&])[A-Za-z\d @ @ @!%?&]{8,}2.6 最少8个最多十个字符,至少1个大写字母,1个小写字母,1个数字和1个特殊字符^(?=.[a-z])(?=.[A-Z])(?=.\d)(?=.[ @ @ @!%?&])[A-Za-z\d @ @ @!%?&]{8,10}三、组合正则表达式– 至少1个大写英文字母– 至少1个小写英文字母– 至少1位数字– 至少1个特殊字符– 最少8个长度^(?=.?[A-Z])(?=(.[a-z]){1,})(?=(.[\d]){1,})(?=(.[\W]){1,})(?!.*\s).{8,}$四、c#中使用正则表达式 // 密码复杂度应至少包含三种字符(大写、小写、数字、特殊符号任选三种) private static bool IsWeakPasswordReg(string password) { var reg_val = 0; var pw_txt = password; var reg = @"[*0-9]";//数字 if (Regex.IsMatch(pw_txt, reg)) { reg_val += 1; } reg = @"[*a-z]";//小写字母 if (Regex.IsMatch(pw_txt, reg)) { reg_val += 1; } reg = @"[A-Z ]";//大写字母 if (Regex.IsMatch(pw_txt, reg)) { reg_val += 1; } reg = @"[\W_!@#$%^&`~()-+=]";//特殊字符 if (Regex.IsMatch(pw_txt, reg)) { reg_val += 1; } if (reg_val < 3) { return false; } return true; }
-
正则表达式中的 $ 符号通常用于表示字符串的结束位置,但当你在替换操作或者某些特殊上下文中提到 $ 后跟数字(如 $1, $2, etc.),这并不表示结束位置,而是引用之前正则表达式捕获组的内容。以下是使用 $ 引用捕获组的几个示例:示例 1:简单替换假设我们有一个字符串,并希望通过正则表达式捕获其中的部分内容,然后在替换时使用这些捕获到的内容。12345let text = "Hello, my number is 123-456-7890.";let pattern = /(\d{3})-(\d{3})-(\d{4})/;let replacedText = text.replace(pattern, "Phone: $1-$2-$3");console.log(replacedText);// 输出: Hello, my number is Phone: 123-456-7890.在这个例子中,正则表达式 (\d{3})-(\d{3})-(\d{4}) 定义了三个捕获组,分别匹配区号、中间三位和后四位数字。替换时,$1, $2, 和 $3 分别引用这三个捕获组的内容。示例 2:逆序姓名如果有一个姓名字符串,格式为 “Lastname, Firstname”,想把它转换为 “Firstname Lastname”。12345let fullName = "Doe, John";let namePattern = /(\w+),\s+(\w+)/;let reversedName = fullName.replace(namePattern, "$2 $1");console.log(reversedName);// 输出: John Doe这里,$1 引用了姓(Lastname),$2 引用了名(Firstname),在替换字符串中交换了它们的位置。示例 3:添加HTML标签给文本中的某些词添加HTML标签,比如加粗关键词。12345let content = "This is a sample text with some keywords.";let keywordPattern = /(keywords)/i;let highlightedContent = content.replace(keywordPattern, "<strong>$1</strong>");console.log(highlightedContent);// 输出: This is a sample text with some <strong>keywords</strong>.这里,$1 引用了匹配到的关键词,并将其包裹在 <strong> 标签中以加粗显示。
-
0.1 日期格式校验以下日期校验可满足“四年一闰,百年不闰,四百年再闰”yyyyMMdd1^(?:(?!0000)[0-9]{4}(?:(?:0[13578]|1[02])(?:0[1-9]|[12][0-9]|3[01])|(?:0[469]|11)(?:0[1-9]|[12][0-9]|30)|02(?:0[1-9]|1[0-9]|2[0-8]))|(?:(((\d{2})(0[48]|[2468][048]|[13579][26])|(([02468][048])|([13579][26]))00))0229))$yyyy-MM-dd1^(?:(?!0000)[0-9]{4}\-(?:(?:0[13578]|1[02])(?:\-0[1-9]|\-[12][0-9]|\-3[01])|(?:0[469]|11)(?:\-0[1-9]|\-[12][0-9]|\-30)|02(?:\-0[1-9]|\-1[0-9]|\-2[0-8]))|(?:(((\d{2})(0[48]|[2468][048]|[13579][26])|(([02468][048])|([13579][26]))00))\-02\-29))$0.2 时间格式校验hhmmss12 小时制,范围为 000000 - 1159591^(?!120000)(?:0[0-9]|1[12])(?:[0-5][0-9]){2}$24 小时制,范围为 000000 - 2359591^(?!240000)(?:[01][0-9]|2[1-4])(?:[0-5][0-9]){2}$hh:mm:ss12 小时制,范围为 00:00:00 - 11:59:591^(?!12\:00\:00)(?:0[0-9]|1[12])(?:\:[0-5][0-9]){2}$24 小时制,范围为 00:00:00 - 23:59:591^(?!24\:00\:00)(?:[01][0-9]|2[1-4])(?:\:[0-5][0-9]){2}$0.3 使用方式String uncheckedStr = "2023-12-12"; final String REGEX_PATTERN = "^(?:(?!0000)[0-9]{4}\-(?:(?:0[13578]|1[02])(?:\-0[1-9]|\-[12][0-9]|\-3[01])|(?:0[469]|11)(?:\-0[1-9]|\-[12][0-9]|\-30)|02(?:\-0[1-9]|\-1[0-9]|\-2[0-8]))|(?:(((\d{2})(0[48]|[2468][048]|[13579][26])|(([02468][048])|([13579][26]))00))\-02\-29))$"; if (!Pattern.matches(REGEX_PATTERN, uncheckedStr)) { throw new BusinessException(ErrorCodeEnum.INVALID_TIME_PATTERN); } 1 日期校验正则表达式解析以 yyyyMMdd 为例解析日期校验正则表达式组装过程匹配前四位年份,匹配范围为 0001-9999 ,使用 (?!) 排除 0000 ,获得 yyyy 部分的校验正则表达式1(?!0000)[0-9]{4}由于月份与日期关联存在多种可能,因此采用模式匹配 1. 31 天的月份 01 03 05 07 08 10 12 (?:0[13578]|1[02]) 匹配月份 (?:0[1-9]|[12][0-9]|3[01]) 匹配日期 01 - 31 2. 30 天的月份 04 06 09 11 (?:0[469]|11) 匹配月份 (?:0[1-9]|[12][0-9]|30) 匹配日期 01 - 30 3. 02 月存在闰月的问题,且条件较为复杂,因此先匹配 01 - 28 的日期范围 02 匹配月份 (?:0[1-9]|1[0-9]|2[0-8]) 匹配日期 01 - 28 使用 | 组装匹配模式,多个模式使用 (?:MODELA|MODELB|MODELC) 的方式进行组合,此处组合匹配模式后获得 mmdd 部分的校验正则表达式123匹配 MMdd 的表达式(?:(?:0[13578]|1[02])(?:0[1-9]|[12][0-9]|3[01])|(?:0[469]|11)(?:0[1-9]|[12][0-9]|30)|02(?:0[1-9]|1[0-9]|2[0-8])) |-- 31 天的月份日期 --|-- 30 天的月份日期 --|-- 28 天的月份日期 --|拼接第 1 步和第 3 步的匹配模式以组装基本的 yyyyMMdd 模式,该模式下不考虑闰年,因此将第 2 步的二月的日期匹配范围改到了 29,该模式无法辨认 1900-02-29 的非闰年情形12不考虑闰年的简易模式(二月的日期匹配范围改到了29,以下模式能正常使用)^(?!0000)[0-9]{4}(?:(?:0[13578]|1[02])(?:0[1-9]|[12][0-9]|3[01])|(?:0[469]|11)(?:0[1-9]|[12][0-9]|30)|02(?:0[1-9]|1[0-9]|2[0-9]))$进一步处理闰年年份123451. 非百年的年份处理较为简单,枚举 4 的倍数且不为 100 的倍数的年份((\d{2})(0[48]|[2468][048]|[13579][26])2. 百年年份保留 400 的倍数(([02468][048])|([13579][26]))00)拼接模式以匹配闰年日期 yyyy022912(((\d{2})(0[48]|[2468][048]|[13579][26])|(([02468][048])|([13579][26]))00))0229|-- 非百年 --|-- 百年(保留400年) --|结合第 3 步和第 6 步的结果组装最终的匹配模式,该模式可以满足 四年一闰,百年不闰,四百年再闰 的需求1^(?:(?!0000)[0-9]{4}(?:(?:0[13578]|1[02])(?:0[1-9]|[12][0-9]|3[01])|(?:0[469]|11)(?:0[1-9]|[12][0-9]|30)|02(?:0[1-9]|1[0-9]|2[0-8]))|(?:(((\d{2})(0[48]|[2468][048]|[13579][26])|(([02468][048])|([13579][26]))00))0229))$
-
avaScript 的异步编程已经从回调 (Callback) 演进到 Promise,再到如今广泛使用的 async/await 语法。后者不仅让异步代码更加简洁,而且更贴近同步代码的逻辑与结构,***增强了代码的可读性与可维护性。在掌握了基础用法之后,下面将介绍一些高级用法,以便充分利用 async/await 实现更复杂的异步流程控制。1. async/await 与高阶函数当需要对数组中的元素执行异步操作时,可结合 async/await 与数组的高阶函数(如 map、filter 等)。2. 使用 async/await 优化递归递归函数是编程中的一种常用技术,async/await 可以很容易地使递归函数进行异步操作。3. 在 async 函数中使用 await 链式调用使用 await 可以直观地按顺序执行链式调用中的异步操作。4、使用 async/await 简化错误处理错误处理是异步编程中的重要部分。通过 async/await,可以将错误处理的逻辑更自然地集成到同步代码中。5、异步初始化类实例在 JavaScript 中,类的构造器(constructor)不能是异步的。但可以通过工厂函数模式来实现类实例的异步初始化。6、结合 async/await 和事件循环使用 async/await 可以更好地控制事件循环,像处理 DOM 事件或定时器等场合。通过以上 6 个 async/await 的高级用法,开发者可以在 JavaScript 中以更加声明式和直观的方式处理复杂的异步逻辑,同时保持代码整洁和可维护性。在实践中不断应用和掌握这些用法,能够有效地提升编程效率和项目的质量~
-
package com.guahao.weic.sys.utils;import java.time.Duration;import java.time.LocalDateTime;import java.util.HashMap;import java.util.Map;//密码登录失败次数限制,如:5分钟内登录失败6次,即锁定账户1小时public class AccountLockUtil { private static final int MAX_LOGIN_ATTEMPTS = 6; //五分钟内最多登录失败六次 private static final long LOCK_TIME_IN_MILLISECONDS = 3600000; // 1小时 private static final long LOCK_RESET_TIME_IN_MILLISECONDS = 300000; // 5分钟 private static Map<String, AccountInfo> lockedAccounts = new HashMap<>(); public static synchronized boolean isAccountLocked(String username) { AccountInfo accountInfo = lockedAccounts.get(username); if (accountInfo == null) { return false; } long lockStartTime = accountInfo.getLockStartTime(); long currentTime = System.currentTimeMillis(); // 如果锁定时间已经过去了,重置锁定信息 if (currentTime - lockStartTime >= LOCK_TIME_IN_MILLISECONDS) { lockedAccounts.remove(username); return false; } return true; // 账户仍然被锁定 } public static synchronized void handleFailedLogin(String username) { AccountInfo accountInfo = lockedAccounts.get(username); if (accountInfo == null) { accountInfo = new AccountInfo(); lockedAccounts.put(username, accountInfo); } long currentTime = System.currentTimeMillis(); if (currentTime - accountInfo.getLastAttemptTime() > LOCK_RESET_TIME_IN_MILLISECONDS) { accountInfo.resetFailedAttempts(currentTime); } accountInfo.incrementFailedAttempts(); if (accountInfo.getFailedAttempts() >= MAX_LOGIN_ATTEMPTS) { accountInfo.setLockStartTime(currentTime); } } public static synchronized void handleSuccessfulLogin(String username) { lockedAccounts.remove(username); } private static class AccountInfo { private int failedAttempts; private long lockStartTime; private long lastAttemptTime; public int getFailedAttempts() { return failedAttempts; } public void incrementFailedAttempts() { failedAttempts++; } public void resetFailedAttempts(long currentTime) { failedAttempts = 0; lastAttemptTime = currentTime; } public long getLockStartTime() { return lockStartTime; } public void setLockStartTime(long lockStartTime) { this.lockStartTime = lockStartTime; failedAttempts = 0; } public long getLastAttemptTime() { return lastAttemptTime; } }}登录校验示例代码 try { //判断账户是否锁定 boolean isLock = AccountLockUtil.isAccountLocked(username); if ( isLock ) { throw new WeicException("账号被锁定,请一小时之后重试"); } else { subject.login(passwordToken); AccountLockUtil.handleSuccessfulLogin(username); } } catch (AuthenticationException e) { //记录用户登录失败次数,5分钟内登录失败6次,即锁定账户1小时 AccountLockUtil.handleFailedLogin(username); logger.error("orgLogin登录错误。用户名{},密码{}", authUser.getUsername(), authUser.getPassword()); throw new WeicException("账号或密码错误"); }上述方案在部分复杂环境中无法生效,下面提供第二种方案:package com.guahao.weic.sys.utils;import javax.servlet.http.Cookie;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.util.HashMap;import java.util.Map;public class AccountsLockUtil { private static Map<String, Integer> failedLoginAttempts = new HashMap<>(); private static final int MAX_FAILED_ATTEMPTS = 6; private static final long LOCKOUT_TIME = 60 * 60 * 1000; // 1 hour in milliseconds public static void processFailedLogin(HttpServletRequest request, HttpServletResponse response, String username) { int failedAttempts = 1; if (failedLoginAttempts.containsKey(username)) { failedAttempts = failedLoginAttempts.get(username) + 1; } failedLoginAttempts.put(username, failedAttempts); if (failedAttempts >= MAX_FAILED_ATTEMPTS) { Cookie lockoutCookie = new Cookie("lockout", "true"); lockoutCookie.setMaxAge((int) (LOCKOUT_TIME / 1000)); // set the cookie to expire in 1 hour response.addCookie(lockoutCookie); } } //判断账户是否被锁定 public static boolean isLockedOut(HttpServletRequest request, String username) { Cookie[] cookies = request.getCookies(); if (cookies != null) { for (Cookie cookie : cookies) { if (cookie.getName().equals("lockout") && cookie.getValue().equals("true")) { return true; } } } return false; }}控制器中代码如下: try { //判断账户是否锁定 boolean isLock = AccountsLockUtil.isLockedOut(request,username); logger.info("账户状态 {}",isLock); if ( isLock ) { throw new WeicException("账号被锁定,请一小时之后重试"); } else { subject.login(passwordToken); } } catch (AuthenticationException e) { //记录用户登录失败次数,5分钟内登录失败6次,即锁定账户1小时 AccountsLockUtil.processFailedLogin(request,response,username); logger.info("账户姓名 {}",username); logger.error("orgLogin登录错误。用户名{},密码{}", username, password); throw new WeicException("账号或密码错误"); }
-
正则去除中括号(符号)及里面包含的内容例子:颜色:粉色[10] 尺码:S[5]去掉[ ]及内容:preg_replace("/\[.*\]/", '', $str)处理后效果:颜色:粉色 尺码:S小技巧:可把[ ]改为其他符号应用在需要的地方正则表达式匹配括号里的内容,^和&用法正则表达式匹配括号里的内容包括括号[\(|(].*[\)|)]$1、符号解释.匹配除\n外的字符*匹配多个\转义字符[ ]匹配里面的任意字符,[\(|(] 表示匹配 "(" 或者 "("2、简化,可以不用| 来判断 "(" 还是 "(" 。[\((].*[\))]坑1:注意 ^ 或者 $ 的使用(^:匹配输入字符串开始的位置;$:匹配输入字符串结束的位置),不要轻易写在最开始或者结尾,加了后匹配不了包含的字符,^[\((].*[\))]$ 表示以左括号开头并且以右括号结尾的字符串,所以匹配不了。要用^或者$ 的表示包含括号内容的字符串写法为[\((^].*[\))$]或者[\((^].*[\))]3、js使用console.log("验证结果",/[\((].*[\))]/.test("fgrgreregr((sdi啥@#@!!#!的s)dd))sdsnhyh"))
上滑加载中
推荐直播
-
全面解析华为云EI-API服务:理论基础与实践应用指南
2024/11/29 周五 18:20-20:20
Alex 华为云学堂技术讲师
本期直播给大家带来的是理论与实践结合的华为云EI-API的服务介绍。从“主要功能,应用场景,实践案例,调用流程”四个维度来深入解析“语音交互API,文字识别API,自然语言处理API,图像识别API及图像搜索API”五大场景下API服务,同时结合实验,来加深开发者对API服务理解。
去报名 -
企业员工、应届毕业生、在读研究生共探项目实践
2024/12/02 周一 19:00-21:00
姚圣伟 在职软件工程师 昇腾社区优秀开发者 华为云云享专家 HCDG天津地区发起人
大神带你一键了解和掌握LeakyReLU自定义算子在ONNX网络中应用和优化技巧,在线分享如何入门,以及在工作中如何结合实际项目进行学习
即将直播 -
昇腾云服务ModelArts深度解析:理论基础与实践应用指南
2024/12/03 周二 14:30-16:30
Alex 华为云学堂技术讲师
如何快速创建和部署模型,管理全周期AI工作流呢?本期直播聚焦华为昇腾云服务ModelArts一站式AI开发平台功能介绍,同时结合基于ModelArts 的实践性实验,帮助开发者从理论到实验更好地理解和使用ModelArts。
去报名
热门标签