本文未完成,部分测试方法、条件或结果可能有误,请谨慎参考! :)
本文基于 MySQL 的 InnoDB BTREE 方法的索引进行测试。
以一张包含 2000 万条记录的表做实验:
CREATE TABLE `dt_read` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`time` datetime(0) NOT NULL,
`a_id` int(11) NOT NULL,
PRIMARY KEY (`id`) USING BTREE
);这张表是用于记录文章点击量的,
`id` 为主键,int(11) 自增;
`time` 为非空 datetime,表示文章打开时间,测试数据是从 2017-03-11 至 2018-04-28;
`a_id` 为非空 int(11),表示文章 ID,在此表中不唯一,测试数据是从 1 至 260218。
体验“全表扫描”
首先来体验一下什么是全表扫描,执行下面语句:
SELECT * FROM `dt_read` WHERE `time` < '2020-1-1' LIMIT 10
> 时间: 0.012s
SELECT * FROM `dt_read` WHERE `time` < '2000-1-1' LIMIT 10
> 时间: 7.317s
表中数据是按主键从小到大排列的,当查询条件为 `time` < '2020-1-1' 时,能很快地从表的前端找到 10 条满足条件的数据,所以不再继续判断后面的记录,立刻返回结果,耗时 0.012 秒;但当条件改为 `time` < '2000-1-1' 时,同样逐条判断,直到最后一条也没有找到,这种情况就是所谓的“全表扫描”,耗时 7 秒。
索引对 ORDER BY 的 ASC 和 DESC 的影响
我们给 `time` 建一个索引,同样执行刚才需要全表扫描的语句:
SELECT * FROM `dt_read` WHERE `time` < '2000-1-1' LIMIT 10
> 时间: 0.012s
创建 `time` 的索引后,相当于生成了一张按 `time` 字段排列的新表,这时 MySQL 就能够很快地定位并找到符合条件的记录,避免了全表扫描。
试试按 `time` 倒序排:
SELECT * FROM `dt_read` WHERE `time` < '2000-1-1' ORDER BY `time` DESC LIMIT 10
> 时间: 0.013s
结论:索引对 ORDER BY 的顺序(ASC)和倒序(DESC)都是有效的。
索引字段的次序对 WHERE 和 ORDER BY 的影响
删除所有索引,创建一个新的索引,字段依次为 `time`, `a_id`。
分别执行以下查询:
SELECT * FROM `dt_read` WHERE `time` < '2000-1-1' AND `a_id` < 0 LIMIT 10
> 时间: 0.013s
SELECT * FROM `dt_read` WHERE `a_id` < 0 AND `time` < '2000-1-1' LIMIT 10
> 时间: 0.013s
结论:MySQL 会自动优化 WHERE 条件的次序来匹配最合适的索引。
但在 ORDER BY 中却不是这么回事了:
SELECT * FROM `dt_read` ORDER BY `time`, `a_id` LIMIT 10
> 时间: 0.013s
SELECT * FROM `dt_read` ORDER BY `a_id`, `time` LIMIT 10
> 时间: 14.066s
原因也很好理解,对两个字段进行排序,先后次序肯定会影响结果集,因此只能以 SQL 语句指定的字段次序来 ORDER BY,这样,按索引的字段次序进行 ORDER BY 查询无疑是更快的。
索引中的字段必须依次使用
保持上例创建的索引不变,即 `time`, `a_id`。
SELECT * FROM `dt_read` WHERE `time` < '2000-1-1' AND `a_id` < 0 LIMIT 10
> 时间: 0.013s
SELECT * FROM `dt_read` WHERE `a_id` < 0 LIMIT 10
> 时间: 6.438s
上句合理利用了索引的字段,而下句跳过了 `time`,直接 WHERE 了 `a_id`,这是不受该索引支持的。
我们可以想象一下这张由索引生成的虚拟表,其实就是一张普通的平面二维表格,按索引指定的字段次序进行了排序,所以全表中仅仅是索引指定的第一个字段是按大小排列的,第二个字段是在第一个字段值相同的区域内按大小排列,后同。所以,跳过索引指定的第一个字段直接对第二个字段进行检索,是无法应用该索引的。这个结论也同样也体现在 ORDER BY 语句中:
SELECT * FROM `dt_read` ORDER BY `time`, `a_id` LIMIT 10
> 时间: 0.013s
SELECT * FROM `dt_read` ORDER BY `a_id` LIMIT 10
> 时间: 29.566s
WHERE 和 ORDER BY 混合
保持上例创建的索引不变,即 `time`, `a_id`。
先来执行这两句:
SELECT * FROM `dt_read` ORDER BY `a_id` LIMIT 10
> 时间: 12.29s
SELECT * FROM `dt_read` WHERE `time` < '2000-1-1' ORDER BY `a_id` LIMIT 10
> 时间: 0.013s
仅仅 WHERE 了一个 `time`,对 ORDER BY `a_id` 的效率却有质的提升,是因为 WHERE 中的 `time` 和 ORDER BY 中的 `a_id` 一起找到了索引吗?答案是否定的。
我们把时间改大,让它能马上找到符合条件的数据:
SELECT * FROM `dt_read` WHERE `time` < '2020-1-1' ORDER BY `a_id` LIMIT 10
> 时间: 22.34s
为什么这个语句就不走索引了呢?
其实,一个简单的 SELECT 查询语句,首先执行 WHERE,然后 ORDER BY,最后是 LIMIT。每一步都独自去找了索引,而非 WHERE 和 ORDER BY 混在一起去找索引。必须保证每一步是快的,最终才是快的。
当 `time` < '2000-1-1' 时,WHERE 用到了索引,所以很快,ORDER BY 却没有用到索引,但为什么也很快呢?因为 WHERE 的结果集非常小(示例中为 0 条)。
当 `time` < '2020-1-1' 时,WHERE 也用到了索引,但其结果集非常大(示例中为所有记录),再 ORDER BY `a_id` 就非常慢了,因为我们没有创建以 `a_id` 开头的索引。
现在把索引改成只有 `time` 一个字段。
SELECT * FROM `dt_read` WHERE `time` < '2020-1-1' ORDER BY `a_id` LIMIT 10
> 时间: 6.033s
因为索引里有 `
SELECT * FROM `dt_read` WHERE `time` < '2000-1-1' ORDER BY `a_id` LIMIT 10
> 时间: 0.013s
SELECT * FROM `dt_read` WHERE `a_id` < 0 ORDER BY `time` LIMIT 10
> 时间: 6.033s
第二句先 WHERE `a_id`,后 ORDER BY `time` 是不能匹配所建的索引的。
索引中的字段越多越好
分别在创建索引(`time`)和索引(`time`, `a_id`)的情况下执行下面语句:
本例使用 ORDER BY 而不是 WHERE 来测试是因为,在 WHERE 的多个条件下,如果符合前一条件的筛选结果集过小会导致判断第二条件时数据量不足,无法判断索引是否起作用。
SELECT * FROM `dt_read` ORDER BY `time` LIMIT 10
仅创建索引(`time`)的情况下:
> 时间: 0.013s
仅创建索引(`time`, `a_id`)的情况下:
> 时间: 0.013s
SELECT * FROM `dt_read` ORDER BY `time`, `a_id` LIMIT 10
仅创建索引(`time`)的情况下:
> 时间: 15.015s
仅创建索引(`time`, `a_id`)的情况下:
> 时间: 0.014s
可以看到,在索引字段依次使用的前提下,索引字段数不少于查询字段数才能避免全表扫描。
虽然索引中的字段越多越好,但必须依次使用,否则也是无效索引。
索引对 INSERT / UPDATE / DELETE 的效率影响
分别在创建索引(`time`)和索引(`time`, `a_id`)的情况下执行下面语句:
INSERT INTO `dt_read` (`time`, `a_id`) VALUES ('2018-4-28', 260218)
不建索引的情况下:
> 时间: 0.01s
仅创建索引(`time`)的情况下:
> 时间: 0.01s
同时创建索引(`time`)和索引(`time`, `a_id`)的情况下:
> 时间: 0.01s
UPDATE `dt_read` SET `time` = '2018-4-28' WHERE `id` = 20000000(注:存在该 id 值的记录)
不建索引的情况下:
> 时间: 0.01s
仅创建索引(`time`)的情况下:
> 时间: 0.01s
同时创建索引(`time`)和索引(`time`, `a_id`)的情况下:
> 时间: 0.01s
虽然在 INSERT / UPDATE / DELETE 时数据库会更新索引,但从实测数据来看,索引对其效率的影响可忽略不计。
一些误区
“in 语法效率很低”?
in 语法也是应用索引的,网传 in 会比一个一个 WHERE OR 要慢得多的说法是不靠谱的。in 主键和 in 索引同理。
另外:
对于字符串类型,LIKE '%abc%' 是不能应用索引的,但 LIKE 'abc%' 可以。更多关于字符串类型的索引,请查阅全文索引(FULLTEXT)。
索引的字段是可以指定长度的,类似字符串索引指定前面若干唯一字符就可以优化效率。
本文系个人实践总结,欢迎批评指正!
本文记录 Newtonsoft.Json 的用法,System.Text.Json 请参此文。
如何在序列化时间类型时以“年-月-日 时:分:秒”的格式输出?
默认时间类型将序列化为:2017-11-10T18:48:14.1685763+08:00,我们只要 new 一个 IsoDateTimeConverter 即可改变时间类型的输出格式:
var dtc = new IsoDateTimeConverter { DateTimeFormat = "yyyy-MM-dd HH:mm:ss" };
string b = JsonConvert.SerializeObject(DateTime.Now, dtc);如何将对象序列化为可友好阅读的字符串?
序列化后的字符串默认是“紧凑型”的,如:{"a":1,"b":2}
可以将 Formatting 指定为 Indented 即可输出格式化后的字符串,例:
var obj = new { a = 1, b = 2 };
string a = JsonConvert.SerializeObject(obj, Formatting.Indented);结果如下:
{
"a": 1,
"b": 2
}
枚举类型输出为字符串,而非索引值
[Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
更多用法参:https://www.cnblogs.com/DomoYao/p/Json.html
不序列化属性
[Newtonsoft.Json.JsonIgnore]
当值为 null 时不序列化
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
不序列化值为 null 的项
var jSetting = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore };
JsonConvert.SerializeObject(obj, Formatting.Indented, jSetting);
本文不定时更新!
A: MySQL 执行 SHOW FULL PROCESSLIST
Q: 查看连接数和慢查询,适用于 MySQL 数据库无法连接 1040
A: iftop -i eth0
Q: 查看占用带宽的IP(命令:iftop -i eth0 -F ip/24),添加到安全组、防火墙、宝塔的黑名单中。
命令 grep -l "x.x.x.x" /www/wwwlogs/*.log 可以在 wwwlogs 目录下的所有 .log 文件中查找指定的恶意 IP。
A: goaccess -f xxx.log
Q: 实时分析网站日志,查看请求最多的IP
A: net.xoyozo.weblog 日志分析工具
Q: 自制的 Web 日志分析工具,可按多种方式排序,纠出可疑访问
A: 重启 web 服务器
Q: 有时候能解决 CPU 和内存消耗的问题,如果一会儿又升高,则需要找另外的原因
Q: 500 服务器内部错误
502 Bad Gateway
504 Gateway Time-out
A: 查看 php 日志,可能的路径:
/usr/local/php/var/log/php-fpm.log
/www/server/php/[版本]/var/log/php-fpm.log
Q: RDS MySQL IOPS 使用率高的原因和处理
A: 根据时间点查看慢查询
Q: Discuz! 论坛界面错乱、表情不显示、模块缺失、登录失败、发帖失败等等
A: 进入管理中心 - 工具 - 更新缓存,能解决大部分问题
Q: Discuz! 浏览帖子提示“没有找到帖子”
A: 进入数据库,修复表 pre_forum_post 或分表
Q: CPU 100% 或内存 100%,负载100+
A: 原因有很多,以下是一些建议:
Windows 在任务管理器中查看进程
当前是否有正常的大流量访问(譬如民生类论坛的某个帖子突然火了)特别是重启无效的情况
对比网站日志大小可大致确定哪个网站被大量恶意请求。
观察:命令 top
排查:通过关闭网站来确定是某网站的问题,通过关闭功能确定是某功能的问题,如果 nginx 崩溃请参下条
案例:通过修改 mobcent 文件夹名确定是安米的文件被疯狂请求导致的,更新插件和 mobcent 包解决问题。
如果都是正常访问,top 看到很多 php-fpm,而且个个占用 CPU 还不小,那么根据服务器硬件配置来修改 php 的并发量,如宝塔面板在 php 设置 - 性能调整 页,300 并发方案的推荐配置是:
max_children:300
start_servers:30
min_spare_servers:30
max_spare_servers:180另外,memcached 或 redis 的配置也可以进行相应的修改。
另一个案例是 kswapd0 进程占满 CPU,原因是内存不足导致 swap 分区与内存频繁交换数据。同样调整 php 的设置即可。
也可以通过 iftop 来查询占用带宽较多的 IP 并封禁(出方向),如果 CPU 能降下来,那这个 IP 就是罪魁祸首。
* 使用 WAF 的审计 WAF 日志,未使用 WAF 的审计 Web 日志。
Q: 阿里云 ECS 的 CPU 突然达到 100%,并持续到次日 0:00 左右
A: 可能 ECS 是 t5 规格,受 CPU 积分制度限制,积分耗尽时 CPU 不工作。解决方法是更换其它规格产品或升配。
Q: ASP.NET 所在服务器 CPU 突然达到 50% 或 100%,并持续
A: 首先确定哪个网站,再依次排查网站各功能。可能是 HttpWebRequest 请求远程数据时长时间未返回结果导致的程序阻塞。
Q: nginx 服务停止
A: 查看 nginx 日志
WDCP 路径:/www/wdlinux/nginx-1.0.15/logs/error.log
Q: 公网出带宽 100%,其它指标正常
A: Windows 在任务管理器-性能-资源监视器-网络 查看占用带宽的进程PID,然后在任务管理器-详细信息中的找到对应的用户(如果为每个网站分别创建了用户,就能知道是哪个网站占用了带宽);如果是被 PID 为 4 的 System 占用大部分带宽,也可以尝试重启 IIS 来解决。
CentOS 使用 nethogs 查看占用带宽的进程PID和USER,如果为每个网站分别创建了用户,就能知道是哪个网站占用了带宽,否则只能一个个关闭网站来判断,不知道大家有没有好的方法?当然还可以直接用 iftop 命令查看占用带宽的 IP。另外,查看每个网站在那个时间段的日志文件的大小也能大概看出是哪个网站被采集了。
A: Linux 显示每个用户会话的登入和登出信息
utmpdump /var/log/wtmp
参考:http://www.tulaoshi.com/n/20160331/2050641.html
Q: RDS 的 CPU 100%
A: 如果是突然持续占满(同时伴随 ECS 资源使用率下降,页面出现 502),很大可能是受攻击(或社交网站推送突发事件等),查看“慢查询”,添加相关索引;如果是 Discuz! 论坛,可尝试修复优化表 pre_common_session。
如果是数日缓步上升,或新项目上线,考虑 SQL 慢查询,思路:MySQL / SQL Server。
MySQL:SHOW FULL PROCESSLIST
SQL Server:sp_who
Q: php 网站的服务器,内存在数天内缓慢上升
A: 大概是 php-fpm 占用过多,或进程数太多
更改 php 的配置(如 max_spare_servers),执行:service php-fpm reload
Q: 进程 cloudfs 占用内存过多
A: 参:https://xoyozo.net/Blog/Details/cloudfs-cache
Q: RDS 磁盘占用过大
A: 参:https://xoyozo.net/Blog/Details/how-to-use-rds
Q: ECS 受到 DDoS 攻击怎么办?
A: 参:https://xoyozo.net/Blog/Details/aliyun-ddos-without-bgp
Q: 如果 ECS 和 RDS 各项指标都没有异常,但网页打开慢或打不开502,TTFB 时间很长,是什么原因?(ECS 的 CPU 100%,RDS 的连接数上升,也可参考此条)
A: 数据库有坏表,尝试优化/修复表(慢 SQL 日志中锁等待时间较长的表?),或主备切换。show full processlist 时看到许多
DELETE FROM pre_common_session WHERE sid='******' OR lastactivity<****** OR (uid='0' AND ip1='*' AND ip2='*' AND ip3='*' AND ip4='*' AND lastactivity>******)
Q: Discuz! 创始人(站长)密码被改
A: 数据库找到 pre_ucenter_members 表,复制其它的已知登录密码的账号,复制其 password 和 salt 两个字段的值到创始人账号中,创始人账号即可用该密码登录了。
Q: 通过 iftop 观察到,Discuz! 网站从 RDS 数据库到 ECS 网站服务器私网流量非常大,远大于公网流量
A: 可能是缓存出问题了,尝试卸载重装 Redis 来解决。
Q: 宝塔面板中安装的 Redis 经常自动停止
A: 尝试卸载重装 Redis 来解决。
Q: 马甲客户端出现“您的网络有些问题”
A: 原因有许多,其中一个就是新建了一个数据表,然后 /source/class/table/ 下面丢失了对应的文件,具体可以找官方排查原因。
Q: 排查服务器安全需要检查哪些日志?
A: Web日志、登录日志(/var/log/secure)等。
Q: 带宽波形以几分钟为周期呈锯齿状波动是什么原因?
A: 该现象主要由防火墙流量管控机制与检测周期设置共同作用所致。防火墙基于预设的带宽阈值执行安全防护策略,当检测到流量峰值超过设定阈值时,将自动触发限流策略拒绝后续请求。待流量回落至安全阈值后,系统自动恢复服务访问权限。若防火墙的带宽采样检测周期设置过长(如以分钟为单位的检测间隔),将导致系统对实时流量变化的响应出现迟滞。这种周期性的检测机制会使带宽监控数据在阈值临界点附近呈现规律性的锯齿状波动特征。
优化建议:可通过调整防火墙的流量检测周期至更小时间粒度(如10-15秒),或采用动态流量整形策略,以实现更平滑的带宽控制效果。
补充说明:对于阿里云监控数据的调用,建议注意接口调用频率管控。高频调用云监控API接口将触发阿里云的API计费策略,可能产生额外的资源消耗成本。
其它案例
某台 ECS 上的多个网站出现 502,查询到 CPU / 内存 / 带宽 都比平时高,但都未满。用 iftop 看到连接的一个远程 Redis 占用内网带宽非常高。尝试重启远程 Redis 未果。尝试重启 ECS 上的 nginx 未果。尝试重启 ECS 未果。进入 ECS 的宝塔面板,重启 PHP 有效。
公众号的报警群中经常收到这样的消息:
Appid: *
昵称: *
时间: *
内容: 微信服务器向公众号推送消息或事件后,开发者5秒内没有返回
次数: *分钟 *次
错误样例: [OpenID=*][Stamp=*][3rdUrl=http://api.socialbase.cn/extapi/wechat/message/*/][IP=*][Event=Click Menu Url]
报警排查指引,请见: http://url.cn/ab0jnP除此之外还有另外一个问题,就是客户端发送图片后会收到两条回复,一条是“印美图”处理打印图片链接,另一条是识脸判断年龄的图文。前者是之前与印美图公司合作的与快速打印照片设备配合吸粉的功能,后者是跳转到使用 FACE++ 的页面显示图片中人物的年龄。

几天来一直找不出原因,代码中搜索错误关键词无果,被动回复消息整个流程断点逐步调试也没有发现哪里有返回“请点击这里预览印美图 点击此处裁剪相片并打印。”
不是开发模式的问题,那一定在公众平台,登录后终于在“开发”的“基本配置”页找到了“管理已授权的第三方平台”,找到“Socialbase”取消授权即可。

整个世界安静了……

UTC(世界协调时间)和 GMT(格林尼治标准时间)都与英国伦敦的本地时间相同。北京是东八区,即 UTC+8 或 GMT+0800
时间戳是指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数。
翻译成程序员语言就是指当前的本地时间与 1970-1-1 0:00:00 UTC 时间换算的本地时间相差的秒数
或者当前的 UTC 时间与 1970-1-1 0:00:00 UTC 时间相差的秒数
以我在北京时间 2000/1/1 8:00:00 站在东八区为例:
在 JS 中:
// 获取当前本地时间: new Date() // 返回:Jan 1 2000 8:00:00 GMT+0800(中国标准时间) // 获取当前 UTC 时间字符串: (Local Time).toUTCString() // 返回:Jan 1 2000 0:00:00 GMT // 初始化一个 UTC 时间 2000-1-1 0:00:00 new Date(Date.UTC(2000, 1 - 1, 1, 0, 0, 0)) // 获取 UTC 时间的本地时间字符串: (UTC Time).toLocaleString() // 本地时间 1970/1/1 8:00:00 的时间戳 new Date(1970, 1 - 1, 1, 8, 0, 0).getTime() / 1000 // 返回:0 // 本地时间 2000/1/1 8:00:00 的时间戳 new Date(2000, 1 - 1, 1, 8, 0, 0).getTime() / 1000 // 返回:946684800 // 本地时间 当前 的时间戳 new Date().getTime() / 1000 // UTC 时间 2000/1/1 0:00:00 的时间戳 new Date(Date.UTC(2000, 1 - 1, 1, 0, 0, 0)).getTime() / 1000 // 或 Date.UTC(2000, 1 - 1, 1, 0, 0, 0) / 1000 // 返回:946684800
在 C# 中:
DateTime 默认的 Kind 是 Local,使用 DateTime.SpecifyKind() 方法可以定义一个 UTC 时间
DateTime.Now 返回当前本地时间
DateTime.UtcNow 返回当前 UTC 时间
// 定义一个本地时间 2000/1/1 8:00:00 new DateTime(2000, 1, 1, 8, 0, 0) // 定义一个 UTC 时间 2000/1/1 0:00:00 DateTime.SpecifyKind(new DateTime(2000, 1, 1), DateTimeKind.Utc) // 将 UTC 时间转化为本地时间 (UTC Time).ToLocalTime() // 将本地时间转化为 UTC 时间 (Local Time).ToUniversalTime()
再次说明,本地时间和 UTC 时间都是 DateTime 对象,关键看定义的时候是 Local 还是 Utc
// 本地时间 1970/1/1 8:00:00 的时间戳 (new DateTime(1970, 1, 1, 8, 0, 0) - DateTime.SpecifyKind(new DateTime(1970, 1, 1), DateTimeKind.Utc).ToLocalTime()).TotalSeconds // 返回:0 // 本地时间 2000/1/1 8:00:00 的时间戳 (new DateTime(2000, 1, 1, 8, 0, 0) - DateTime.SpecifyKind(new DateTime(1970, 1, 1), DateTimeKind.Utc).ToLocalTime()).TotalSeconds // 返回:946684800 // 本地时间 当前 的时间戳 (DateTime.Now - DateTime.SpecifyKind(new DateTime(1970, 1, 1), DateTimeKind.Utc).ToLocalTime()).TotalSeconds // 将时间戳 946684800 转换为本地时间 DateTime.SpecifyKind(new DateTime(1970, 1, 1), DateTimeKind.Utc).ToLocalTime().AddSeconds(946684800)
实战:
如果我们要将时间戳精确到毫秒,那么 JS 直接 .getTime() 即可,不需要 / 1000,C# 将它转换为本地时间时用 AddMilliseconds 代替 AddSeconds。
中国跨越了多个时区却统一使用北京时间,所以国内网站只要记录本地时间即可;如果做国际站或者有不同国家的访客,除非全部由服务器端获取时间,否则客户端 JS 的本地时间(非时间戳)都需要转换成 UTC 时间来跟服务端的时间进行运算和保存,推荐使用时间戳在客户端和服务端之间传递,因为时间戳与时区无关,它是两个相同性质的时间(同为本地时间或同为 UTC 时间)的差值。
收录了一些个人觉得不错的网页开发插件。
由于插件更新频繁,本页如有错误请指正,也欢迎告知更多功能强大、使用方便的插件。
| 插件 | 简介 | 备注 |
| 框架 | ||
| jQuery | 最流行的 JS 框架 | 下载、中文文档、英文整合文档、中文整合文档,浏览器支持、来自 css88 的文档 官方建议 IE 6-8 使用 1.12.4 |
| Angular、中文版 AngularJS (version 1.x) | 一套框架,多种平台同时适用手机与桌面 | MVC 架构,使得开发现代的单一页面应用程序(SPAs:Single Page Applications)变得更加容易 |
| Vue.js | 是一套用于构建用户界面的渐进式框架。 | |
| Bootstrap、中文版 | 简洁、直观、强悍的前端开发框架 | 英文文档、v3中文文档、v2中文文档、视频教程,主题和模板 |
| jQuery UI | 为 jQuery 提供更丰富的功能 | 示例:Datepicker、Color Animation、Shake Effect |
| 功能 | ||
| jQuery File Upload | jQuery 文件上传 | 英文文档 |
| jQuery Cookie | 读取、写入和删除 cookie | 浏览器支持,文档 |
| json2.js | json 操作库 | 已弃用,旧 IE 用 jQuery 的 parseJSON,HTML 5 用 JSON.parse |
| Lightbox | 老牌图片浏览插件 推荐使用更强大的 Viewer.js | |
| Swiper、中文版 | 最现代的移动触摸滑块(Most Modern Mobile Touch Slider) | 英文文档,中文文档,旧浏览器支持版本:2.x.x,Swiper 2 英文文档,中文文档 |
| jquery-cropper | 图片裁剪 | |
| FastClick | 用于消除手机浏览器上触摸事件触发之间的 300 毫秒延迟 | 用法,不应用的场景 |
| PACE | 页面加载进度条 | 文档,IE8+ |
| toastr | jQuery 通知 | 文档 |
| Autosize | 一款小巧的,可自动调整 textarea 高度的独立脚本 | IE9+ |
| X-editable | 允许您在页面上创建可编辑元素 | 文档,Demo |
| select2 | 一款提供搜索过滤、自定义样式的下拉框插件 | |
| jQuery Tags Input | 标签输入框 | 用法 |
| Viewer.js | 图片浏览插件 | GitHub(viewerjs)、GitHub(jquery-viewer) jquery-viewer 是 viewerjs 的 jQuery 插件,即在 jQuery 环境中要同时引用这两个脚本。 |
| PDF.js | A general-purpose, web standards-based platform for parsing and rendering PDFs. | |
| 编辑器 | ||
| UEditor | 百度在线编辑器 | GitHub 下载、文档、ASP.NET 部署教程 |
| 日期时间 | ||
| bootstrap-datepicker | Bootstrap 日期选择器 | Online Demo |
| DateTimePicker | 日期时间选择 | |
| MultiDatesPicker | 多日期选择 | |
| FullCalendar | 日历日程事件工作表 | IE 9+, jQuery 2.0.0+ |
| TimeTo | 计时、倒计时 | |
| 图表 | ||
| D3.js | D3.js 是基于数据驱动文档工作方式的一款 JavaScript 函数库,主要用于网页作图、生成互动图形,是最流行的可视化库之一。 | |
| Highcharts、中文版 | 兼容 IE6+、完美支持移动端、图表类型丰富、方便快捷的 HTML5 交互性图表库 | 文档 |
| ECharts | 百度图表控件 | |
| AntV | 来自蚂蚁金服的专业、简单、无限可能的可视化解决方案 G2 - 专业易用的可视化类库 G2-mobile - 移动端高性能可视化类库 G6 - 关系图可视化类库 | 流程图, 关系图, 可视化规范, 地图, 河流图, 力导图, 网络图, UML图, 业务流程图, 时序图 |
| SyntaxHighlighter | 功能齐全的代码语法高亮插件(JS) | |
| 动态排名数据可视化 | 将历史数据排名转化为动态柱状图图表 开源代码,非插件,修改使用 | GitHub、视频教程、EV录屏、网页示例、视频效果 |
| 图标 | ||
| Font Awesome | 完美的图标字体 | IE 8+,v3.2.1 支持 IE 7,进阶用法(定宽/边框/动画/旋转/叠加) |
| Glyphicons | 图标字体 | 作为 Bootstrap 组件 |
| Iconfont | 阿里巴巴矢量图标库 | 用户可以自定义下载多种格式的 icon,也可将图标转换为字体,便于前端工程师自由调整与调用 |
| UI 框架 | ||
| WeUI | 同微信原生视觉体验一致的基础样式库 | Demo、Wiki |
| Apple UI Design Resources | 苹果用户界面设计资源 | |
本文适用且不限于 iTunes 12.5,在 Windows 上实现。
iPhone / iPad 的铃声文件是 .m4r 格式的,可以通过 iTunes 将 .mp3 /.wav 等其它格式的音乐文件转换成 .m4r 文件。
打开 iTunes
菜单栏选择:文件 - 将文件添加到资料库 - 从文件资源管理器中选择要作为铃声的音乐文件
如果要截取其中一段音乐作为铃声,则在资料库中右键该音乐 - 显示简介 - 选项,设置开始和停止时间,长度不能超过 40 秒
在资料库中将其选中,菜单栏选择:文件 - 转换 - 创建 AAC 版本
此时在资料库中会多出一个音乐来,右键单击,在 Windows 资源管理器中显示,我们可以看到以原音乐文件名命名的 .m4a 文件(如果看不到扩展名,则在菜单上点击 查看,选中“文件扩展名”即可)
将该文件扩展名改为 .m4r
铃声做好了,怎样导入到手机上呢?简单的答案是用 iTools,其实上面制作铃声的过程也可以用 iTools 一键实现,哈~哈哈~哈哈哈~
知其然,才能使其安——王震
常见的攻击手法
SQL 注入
文件上传
弱口令
Nday 攻击
XSS
社会工程学
等等……
被黑原因总结
| 不知道 | 不及时 | 不在意 |
| 不知道自用系统安全动态 | 不及时更新系统安全补丁 | 不在意个人信息安全 |
| 不知道常见黑客攻击手段 | 不及时修复漏洞 | 不在意用户数据安全 |
| 不知道该如何修复 | 不及时排查被黑系统 | 不在意各种安全软件提示、提醒 |
| 不知道今后该如何防御 | 不在意细节 |
那些年,醉人的“三字经”
| 网站渗透娱乐版 | 针对企业的实战版 |
|
进谷歌 找注入 没注入 就旁注 没旁注 用0day 没0day 猜目录 没目录 就嗅探 爆账户 找后台 传小马 放大马 拿权限 挂页面 放暗链 清数据 |
搞企业 先扫描 默认密 都知道 社工库 找一找 邮箱号 先列好 九头蛇 跑一跑 搞不定 放大招 发邮件 凭伪造 没邮箱 搞网站 二级域 皆可爆 老漏洞 没修好 新漏洞 刷一票 干研发 Git 找 原代码 全都要 CDN 可以跳 防火墙 可以撬 堡垒机 可以绕 云防护 可以秒 是企业 没有哪家搞不了 |
攻击手法统计
Nday攻击:45%
漏洞攻击:35%
其他攻击:15%
0day攻击:5%
一些箴言
80%的安全问题都是已知的安全问题,但是能抵御已知安全问题的网站只有20%
弱口令虽然看起来很弱,但是忽视弱口令只会让你的网站变得更弱
没有百分之百的安全,你所做的一切不是为了让自己无坚不摧,只是让自己不再弱不禁风
80%的系统安全问题都是可以通过升级补丁来解决,但是能做到这点的人只有20%
SQL注入存在十几年了,依然是主流攻击手段,可见安全比的不是谁更先进,而是谁更细心
不要得罪你的开发人员,这就跟你吃饭不要得罪服务员一样,你不知道他下一秒会不会在你的菜里吐口水
还有一句
永远不要觉得你安装的安全防护软件真的可以保护你的安全
服务器安全注意事项
不安装不必要的软件
排查所有系统弱口令
关闭不常用的端口
控制目录权限
不在服务器上下载、打开非官方提供软件
不在服务器上打开他人发来的网页链接
如何排查暗链?
利用查看网站的源代码来检查黑链
使用站长工具“网站死链检测”功能来检查黑链
用 FTP 查看网站文件的修改时间来检查黑链
接入 webscan.360.cn 检测
后门排查
Windows 下,D 盾、安全狗、主机卫士
Linux 下,Seay 一句话扫描脚本、主机卫士 Linux 版
用 FTP 查看网站文件的修改时间来排查恶意后门
接入 webscan.360.cn 等在线检测
安全类书籍推荐
《Web 安全深度剖析》——张炳帅 著
《白帽子讲 Web 安全》——吴瀚清 著
《Web 前端黑客技术揭秘》——钟晨呜(余弦)著
《黑客攻防技术宝典 Web 实战篇》——国外某黑客 著
联系方式
最理想的部署方式是 ClickOnce,但是证书问题会导致安装时提示:
Windows 已保护你的电脑
Windows SmartScreen 筛选器已阻止启动一个未识别的应用。运行此应用可能会导致你的电脑存在安全风险。
这需要一个从 CA 获取的数字证书(http://www.doc88.com/p-785388554071.html)
百科: http://baike.baidu.com/view/1390498.htm
ClickOnce 部署教程: http://www.cnblogs.com/weixing/p/3358740.html
Makecert.exe(证书创建工具): https://msdn.microsoft.com/zh-cn/library/bfsktky3.aspx
如何:为 ClickOnce 应用程序向客户端计算机添加一个受信任的发行者:https://msdn.microsoft.com/zh-cn/library/ms172241.aspx
执行命令:makecert -r -n "CN=嗨秒网" -sv himiao.pvk himiao.cer
Password: LRQelk0l****************FTtJvufI
-r 创建自我签名证书。
-n name 指定主题的证书名称。 此名称必须符合 X.500 标准。 最简单的方法是在双引号中指定此名称,并加上前缀 CN=;例如,-n "CN=myName"。
-sv pvkFile 指定主题的 .pvk 私钥文件。 如果该文件不存在,系统将创建一个。
执行命令:Cert2spc himiao.cer himiao.spc
执行命令:pvk2pfx -pvk himiao.pvk -spc himiao.spc -pfx himiao.pfx -pi LRQelk0l****************FTtJvufI –po LRQelk0l****************FTtJvufI –f
问题描述:
当我们的界面需要在程序运行中不断更新数据时,当一个textbox的数据需要变化时,为了让程序执行中不出现界面卡死的现像,最好的方法就是多线程来解决
一个主线程来创建界面,使用一个子线程来执行程序并更新主界面
这样就不会出现卡死的现像了
这肯定是没有问题的,
但是为什么在使用的过程中一样会有很多地方会出现卡死呢,而且有用户跟我说是我的Httphelper类的问题,其实不是,而且我再次声明我的Httphelper类跟多线程并没有关系。不要在诬赖我了哦。
这个问题其实也困或了我很久,但是今天终于解决了,而且我发现很多人有这样的问题,所以我分享一个例子方便大家参考吧。
先来看看我的界面

当我单击
开始执行后

这个时候界面是不会卡死的,
只是数据在不断的更新
下面看看我的代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace WindowsFormsApplication3
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
//创建一个委托,是为访问TextBox控件服务的。
public delegate void UpdateTxt(string msg);
//定义一个委托变量
public UpdateTxt updateTxt;
//修改TextBox值的方法。
public void UpdateTxtMethod(string msg)
{
richTextBox1.AppendText(msg + "\r\n");
richTextBox1.ScrollToCaret();
}
//此为在非创建线程中的调用方法,其实是使用TextBox的Invoke方法。
public void ThreadMethodTxt(int n)
{
this.BeginInvoke(updateTxt, "线程开始执行,执行" + n + "次,每一秒执行一次");
for (int i = 0; i < n; i++)
{
this.BeginInvoke(updateTxt, i.ToString());
//一秒 执行一次
Thread.Sleep(1000);
}
this.BeginInvoke(updateTxt, "线程结束");
}
//开启线程
private void button1_Click(object sender, EventArgs e)
{
Thread objThread = new Thread(new ThreadStart(delegate
{
ThreadMethodTxt(Convert.ToInt32(textBox1.Text.Trim()));
}));
objThread.Start();
}
private void Form1_Load_1(object sender, EventArgs e)
{
//实例化委托
updateTxt = new UpdateTxt(UpdateTxtMethod);
}
}
}
就这些代码,大家看注释应该就明白一点了,
主要是使用一个委托来更新界面的richTextBox1
这样写是肯定没有问题的,而且在我其它的更高级一点的例子里也是这么写的
C#多线程|匿名委托传参数|测试网站压力--升级版
http://www.sufeinet.com/thread-13-1-1.html
上面的文件大家可以做为参考
那问题现在那里呢,其实就出在这一句上
this.BeginInvoke(updateTxt, "线程结束");
大家也许已经发现了,我是这样写的,而不是
updateTxt("线程结束");
这样来直接在子线程中使用,
我相信有很多同志都是这样写的,其实错就错在这里
如果直接使用
updateTxt("线程结束");
大家想一下应该就明白了,
updateTxt是在主线程创建的,而我们在子线程中直接使用,运行的数据多了,就会出现卡死,这是界面信息堵死的原因,
所以就算是委托也不能直接在子线程中使用,而是要使用BeginInvoke方法来调用这个委托
这样才不会出现卡死的现像。
问题就解决了。
大家支持一下哦
下面是我的源码提供给大家下载吧
WindowsFormsApplication3.zip (49.65 KB)