0%

延宕其实直白的说就是拖延的意思,有人就感觉了,装逼非要搞个不常见的,就是因为不常见所以你才会好奇啊,才会去查一下这个词时代表什么意思。良苦用心在于为了加深印象撒。

正文

此篇内容源起最近要准备进行一次分享,筛选分享主题时,想到了拖延,首先我自身就有这个问题,然后我敞开怀抱感受了一下,身边很多人都或多或少存在拖延的问题。

目录

  • 拖延原因分析
  • 拖延的特征
  • 造成的危害
  • 怎么破

首先这篇不是一个从心理学角度写的东西,当然咱也没这个段位。这是一个不严谨但具有严重个人色彩的分享,只在于刨析自己从而能给朋友们提供一些思考和建议。

拖延原因分析

白话点说可能有下面四个原因:

  1. 对成功所需的能力缺乏自信
  2. 对要去完成某个任务有反感心理:认定做事的过程中会遭遇很多困难,结局也会很惨
  3. 目标和回报太遥远,感受不到对我有什么意义
  4. 无法自我约束,例如容易冲动和分心

加粗部分是我认为对我影响最突出的部分。

首先咱们得说导致拖延的因素有很多,具体你是哪一类,你可以买本《拖延心理学》对号入座。我暂时认为自己时拖延早期患者,所以列出的主要是自己审视有的。

目标和回报太遥远,感受不到对我有什么意义

先分析一下,目标和回报太遥远,感受不到对我有什么意义,这个点其实很有意思,你回过头看一下自己列的目标也好还是flag之类的…,大多数都会有一个比较共通的点,那就是列的太大太虚,然后也没有反馈的环节。

上图所示就是以前我列的目标,注意看打勾的标识完成的,红圈的表示未达成的。我来自我检讨一下啊,首先打圈的一看就不符合smart原则,当然也没法用PDCA那套。第二个原因是这几个都没有进行反馈设定,这就让你总感觉这个目标好像老离我挺远,慢慢的就觉得没意思了,也没用积极性了。

但是相反打勾的我都完成了,主要有两方面的原因。

  1. 这几个都是有明显的反馈环节的,比如团队分享,首先意义对我和对同事而言都是正向的。分享完之后也能收到同事给与的一些讨论和评价,这也是一个反馈的环节。这就让这件事变得有结束有结果有意义了,当然就有积极性。
  2. 这件事很具体,也比较小,跨越的周期不长,比较符合smart原则,事情就变得可达。
无法自我约束,例如容易冲动和分心

先根据 Tim Urban在TED的演讲,刨析一下拖延时的大脑活动情况,我觉得真是讲到我心里去了,具体大家可以搜一下演讲的名字叫<你有拖延症吗>。

如上图在有拖延症的大脑里会有一只Monkey(分心/诱惑),它经常会跳出来,告诉你其实你的时间还有很多,要不我们逛逛YouTobe、BiliBIli…,它会不断的骚扰你,最终你会沦陷让其掌握大脑。其实就是抵御不了诱惑,容易分心。那什么时候我们会突然警醒呢,就是有一个东西出现的时候,如下图,这个东西叫恐慌。它一来Monkey就被吓跑了,但是往往这个时候,已经来不及了,被动了。

拖延特征

我们说说怎么辨别,你是否存在拖延这个问题。

  1. 看它是不是让你烦恼不已

    内在结果:必须承受某些内在情绪的折磨,从恼怒、后悔到强烈的自我谴责和绝望

    外在结果:影响家庭、工作、社交….

  2. 在一开始,你往往信心满满

    在完成目标的一开始,往往信心满满 ,但是最后其实都不能很好的的完成或者说完成不了,往往整个过程如下图。

  3. 自我

    自我价值感 =能力(具有独立性,反对受控制) =表现(通过拖延,“我”说了算),不愿意遵守那些不是我们自己所制定的规则并顺应别人的需要 。

  4. 追求完美

    咋一看还挺牛x,原来拖延还有这么美丽的特征,但是注意我们这儿说的是适应不良型的完美主义,“完美主义”者往往对自己期待过高,不够现实,当无法实现这样的要求是,就不知所措。失望之余,通过拖延让自己从中退却。适应不良型的完美主义,对自己的要求跟对自己的表现的期待之间存在一种矛盾。

拖延的伤害

怎么破

说了那么多,最终咱们得找到解法,当然前提是你有拖延困扰并且你愿意付诸行动改变这个毛病。

以下是我亲身实践且认为效果良好的方子,现在我也还在这么做,这是个持久战别想着10天半个月就有多大的改变,也别相信什么21天就能养成xx习惯,普通人就踏踏实实干就行了。

破法1:你得接受
  • ​ 接受自己能力有限这个事实得人不太会为此过于烦恼 。
  • ​ 接受遵守那些不是我们自己所制定的规则并顺应别人的需要。
破法2:和原因对上号
  • 看看这方面的书以及专业的一些心理视频或者找心理方面的人士咨询,找到自身造成的拖延的原因,才能对症下药,人是个体,个体就有差异千万别总去套别人那套方法论,要找到适合自己的。
破法3:明确的目标与可行性的计划

找到一个目标,然后将它分解成几个小的步骤,跨出小小的第一步,学习怎样记录时间,以及如何优化周围环境使之向有利于成功的方向推进。

  • 目标smart且够小,可达。既非常小,又可以给你带来进步感和成就感。

  • 执行过程中引入监督、奖惩机制

  • 整个执行目标的过程按照PDCA不断循环

  • 训练强大的执行力

    执行能力的基本要素:注意力控制、 认知弹性、 目标设定、 信息处理

    1.启动任务(起始,产生行动的想法)。

    2.维持注意力(持续跟进,专注于一个事项)。

    3.抑制冲动(在行动前有所思考,而不是马上反应)。

    4.转换注意力(从一个事项到另一个事项,转变关注的焦点,有弹性地加以回应)。

    5.流程记忆(记得计划、指令和以前学到的知识,在学习新知识和应对新环境的时候可以记起和运用到旧的知识)。

    6.情绪控制(调整和管理情绪)。

    7.组织材料(获取所需的材料,并依序编排)。

    8.自我监测(具备自我评价的相应语言能力,在必要的时候能够通过自我交谈闯过难关)。

    9.时间管理(时间意识,以及对待时间的务实态度)。

    10.计划(按优先次序考虑问题,找出达成目标的各个步骤,提前为以后的需要和相关进程做好准备)

破法4:学会怎样判断时间**

时间四象限

学会利用零碎时间

预防意外干扰,抵制诱惑

不要太分散精力

找出你的最佳时间

享受你的“自由”时间

  • 主观时间和客观时间,做到平滑过渡。很多人就是忽略客观时间所以才老是导致拖延,时间不是跟着你的意志走的。
  • 列出“非计划”时间,除开必须做的事情,剩下多少时间可以用于实现你的目标,给他排出来。
  • 积极的时间约束(番茄工作法…),主要是提高专注力,人不可能24小时都是专注的,就算你说你可以那请你看看猝死的例子…
破法5:积极一点

记住一点:不断地否定自己或者消极对待是要消耗很多能量地。

领导告诉了我一句话:如果你今年没觉得去年的自己是个SB那你就没有在成长,所以别动不动就沮丧、消极。

所以又对应上前面说的,要从一个个小成就不断地激励自己。

破法6:利用你的身体减轻拖延

锻炼,很多人一提到锻炼就会马上接一个词“身体”,其实锻炼不仅仅是锻炼身体其实还是一种脑力的、心理的活动,锻炼是一种释放,通常锻炼你是不会受其他东西影响的,比如你不能玩手机不能看电视等等…这就迫使你专注起来,并且大脑会开始想事情,有点类似冥想的意思。

你的大脑是比较放空的,你可以进行整理、归纳、思考等一系列活动,同时锻炼完事之后又特别爽,释放了身体和心理上的一些无用的东西。

今天内心膨胀的以为自己是个人才,所以随心所欲的看了门课。以下记录了我觉得对我有意义的点。

根据业务布局和业务的洞察来理解和分析业务的变局时什么,再次基础上呢再来看搭建什么样的阵型,组织阵型来匹配业务,为了这样的一个人才搭建,需要准备怎样对人才进行赋能,这个赋能是系统性的赋能,不是对单个个体,甚至不是对团队,而是一个系统性的赋能。最后沉淀褚一套人才管理的机制,用这样的一套人才管理机制不断推动人才。

人才

业务布局=人才体积

人才体积:人才在多大的业务空间中去发挥作用,所以业务布局决定了人才体积

组织阵型=密度

人才分布的密度和人才分布的层次

人才赋能=人才质量

对组织化导向的人才赋能,我组织想对我整个的人才产生怎样的一个牵引力。核心是我是要提高我得人才适应未来业务成长需求,适应未来变局的整体的能力的拉伸。

密度=质量/体积

所以单独对人才进行培训和赋能是不够的,而是要对人才的密度进行一个拉升,即提升人才质量的同时,要让业务体积处于合适的范围内。

人才称重:人才在组织中的重量,发挥的作用。

人才称重的三种方式:

  1. 通过人才赋能提升人才质量
  2. 通过业务布局减少人才体积(冗余)
  3. 通过组织机构的调整来优化人才在不同组织单元中的密度,激活组织的有效性。

四大模型

主要说说人才管理机制模型:

汰换、激励、约束、牵引

汰换:这是一个必然的过程,当你想懈怠的时候觉得无趣的时候,问问自己你对于公司的价值是什么

牵引:企业文化价值的输入、企业向心力的培养等

业务变局

业务结构与人才结构

解释,在什么情况下先发展业务还是先发展人才。

依赖的手段则是进行业务摸底人才摸底(核心团队)

组织变阵

说明什么地方配置更加优秀的人才,合理的调整人才结构和组织结构

人才赋能

迎接未来面对变局的能力

人才管理机制

通过上述内容,沉淀出一套符合自己公司的人才管理机制

小结

从这个课我知道了人才管理不是我之前那么单纯的理解,很容易被这个词午到,人才管理其实不仅仅说的是人才管理,还包括业务布局、组织变阵、人才赋能、机制建立等因素。

所以我理解一下下,人才的定义是不是:专业技能过硬,有战略眼光且能适应业务未来的变局,且有组织向心力?

为什么要谈个人发展?

这个话题其实我很怕的….,因为我发育迟读书少,所以一直都懵懵懂懂+凄凄惨惨戚戚,自认为放荡不羁其实就是无知逗逼。我是从17年开始才意识到有个概念叫“以后的路咋走”,文气点就是个人发展。因为17年开始面临买房、小孩儿上学等一系列问题,深深感到自己的无力,表象就是缺钱,内里就是焦虑。那段时间常常展开双臂抬头望问天“咋整?我该咋整?”,夜深人静常常哭湿了我的小黄人枕巾。就想着不能这样,得变,得抗。

这两年其实我一直在摸索适合自己地发展路径,包括之前地一篇也在写Post not found: 个人定位,从个人定位=>个人发展,我认为应该是这样地顺序,虽然现在个人发展长远地战略还不是非常明确,但是至少我认识到了个人发展地重要性,并且找到了最近3-5年自己地发展路径。

当然这篇不是来说我的,是结合之前老大的分享以及平时自己的学习来试着说明一下,个人发展的必要性。

**我们先聊聊几个点,看是否能达成共识。达不成共识可能这篇文章对你来说就没什么意义 **

工作压力大,没时间

不用我说大家都知道,个人发展是需要时间来铺垫的,同时个人发展肯定跟工作会有联系,这种联系根据个人的处境可强可弱。另外一个共识点是,工作肯定会压缩我们的可自由支配的时间。所以很多时候我们会得出一个结论,工作压力大,没时间。作为程序员我承认确实会存在这样的情况,究其原因:公司的业务压力大,需要堆人堆时间来跟上时代的节奏。另外一点则是个人的精力有限,就像电池一样,在工作上就把电耗尽了,就算会有一些休息时间,也已经没电了。但是我们可以这么想想:现在的工作强度是否有利于个人发展?得到报酬能否多到让我暂时放弃个人发展的程度?工作压力是否真的有我们想象得那么大,时间是否真的就没了?

所以核心的问题是,我们对个人发展这件事情有多重视?愿意投资多少时间和精力?

我的观点是:如果光感受到工作压力大让你没有时间,但又无法获得一些正反馈,那这不是你有没有时间得问题,而是先考虑这份工作是不是应该继续做下去的问题。如果有正反馈,我们再想想是否现在处境就算我想要的的”个人发展”。

怎么来判断,我通常是这样做的:

  1. 列出来公司的晋升制度,薪酬制度。
  2. 尽可能的根据各种反馈,试着评估一下公司的发展前景或者产品线的发展前景。
  3. 列出来所在职位的工作内容(在不晋升的情况下),以及如果晋升了的工作内容(从与领导交流,加上观察基本上能预估出80%左右)。
  4. 列出来如果因为某些因素,导致被动的离开公司,自己会怎样?

不出意外你列完之后,会说一句“卧槽xxxx”,这样就对了,好好考虑一下个人发展的重要性吧。

有点扯远了,其实我是想说,自己愿意的话,不会没有时间。

工作生活要平衡

我不想这么辛苦,我期望生活和工作平衡

很多人都期望活少钱多还开心,朋友圈那些天天晒美食,旅行,老婆孩子热炕头的生活就是理想人生。每个行业都有其辛苦的部分,这才是现实。有的要付出体力之苦,有的要付出健康的代价,有的要付出脑力之苦。既然选择了薪酬相对高一些的IT行业,持续学习新技术,新知识就是你必须面对的。你是想要今天的生活和工作平衡,还是中年油腻后的生计艰难?

假如你不是富二代,官二代,还是更现实,更长期地看待工作和生活平衡的事情。如果你从事的工作是你热爱的工作,不存在平衡问题,从中获得的成就感就是你生活的一部分。如果你从事的工作是你谋生的手段,想持续获得这个收入,就遵循这个工作的本质规律。

以上是老大的原话我觉得已经说的很透彻了,我认为要想追求工作生活的平衡是不可能的,当然我不是说工作和生活就必须得纠缠在一起才好,我是觉得平衡这词应该是心理上的划分而不是物理上的划分。

个人发展战略

然后我们再来说怎么找到属于自己的个人发展战略,内容总结来自圈外商学院的个人发展战略主体纲要,因为平台不让看了,我就直接不要脸的引用有识之士的了。大家如果觉得有用请去链接点赞,就当我对其微薄的回报了。

一、一个模型,帮你找到真正热爱的工作

  • 冰山模型;美国著名心理学家麦克利兰

    • 显性30%;

      • 知识(专业,书籍),慌乱
      • 技能(编程,技术),焦虑
      • 能力(思考能力,学习能力),挫败低效
    • 隐性70%;

      • 价值观(判断事物标准),矛盾纠结
      • 性格特质(行为偏好),心累
      • 动机(成就动机,权力动机),没热情
    • 四个步骤找到适合的工作

      • 找专业;找自己喜欢的专业和爱好的相关岗位
      • 搜索岗位;在招聘网上,搜索岗位的要求
      • 分析需求;用冰山模型,分析这份岗位需要的知识,技能和能力
      • 对比自己;用冰山模型匹配自己的价值观,性格特质和动机,确定适不适合。

二、四大要素,决定你的市场价值

  • 用冰山模型说明该投入到哪里,才能提升自己的市场价值

    • 投入知识;容易获取,但如果不能运用来解决问题,几乎没有竞争力。
    • 投入技能;有门槛,但市场价值取决于稀缺程度,所有技能都会走向供需平衡,高收入不可持续,需要不断持续学习新技能。
    • 投入能力;能力可迁移,积累到一定高度,行业不对称,也能发挥作用。
    • 投入自我发现;难以改变和发现,但如有清晰的认识,找到相匹配的工作也能提升价值。
  • 为什么大多数人都选择投入到知识和技能,不断碎片化学习,练习并不稀缺的技能。

    • 因为知识和技能容易习得
    • 惰性让自身受限于岗位
    • 没明白工作本质是解决问题
  • 汇总;我们的时间,永远应该花在正确的事情上,而不是容易的事情上。

三、四类迹象,发现你的隐藏能力

    • 虽然成功的道路有千万条,但成功人士基本都在遵循了一个原则,就是将自己的自身天赋发挥到了极致。
    • 天赋就是隐藏的能力,让一个人可以在同样起点的情况下,更加加速成长。
  • 天赋探索方法;“SIGN”

    • 自我效能(Self-efficacy);对某类事情非常有信心,觉得自己肯定能做好。
    • 本能(Instinct);迫不及待想要尝试的事情
    • 成长(Growth);发现自己明显比别人进步的快一些
    • 满足(Needs);做完后及时很累,也会觉得满足
  • 如何在日常中发现自己的SIGN特质

    • 围绕SIGN特质问自己

      • 自我效能;认为自己能教别人什么?别人向你请教什么?跟别人聊天倾向聊什么?聊什么话题会让你感到自信?做什么事情不会感到焦虑和担心?
      • 本能;做什么事的时候很少拖延?长时间休息后,你最想念工作的哪个方面?你宁愿放弃休息时间也要做的事情是什么?
      • 成长;什么事情会让你沉浸其中忘记时间?不容易感到疲累和厌烦?
      • 满足;过去工作和生活中,有什么让你获得巨大的成就感和满足感?
    • 围绕SIGN特质问他人

      • 你觉得我身上有什么不同于别人的特质?

      • 你最欣赏或者佩服我的方面是什么?

      • 在你看来,我做什么的时候最兴奋?

      • 我做过什么让你印象深刻的事情么?

      • 在以下方面,你觉得我那些更加擅长?

        • 思维方式;条理清晰,逻辑严密,脑洞很大,专注专业
        • 沟通协调;化解冲突,争取资源,知人善用
        • 计划执行;执行力强,强求完美,目标导向

四、三种方法,将知识内化成能力

  • 惰性知识;不能及时有效调用,占用大脑内存的知识

  • 如何把知识内化成能力,让自己的能力快速提升的三个方法

    • 1.掌握20%的核心;二八原则,一个领域的20%的核心内容,能够解决80%的问题

      • 如结构化思维20%的三个特征;主题鲜明,归类分明,逻辑递进。
      • 擅长找师傅,找领域内专业人士,了解领域的核心20%
    • 2.知识和问题相互靠

      • 让知识和问题链接起来,知识向问题靠,问题向知识靠。

      • 知识(想应用)问题;看到一个知识就去思考这个知识可以用来解决什么问题?

        • 如;马斯洛的五层次需求,可以用来分析奢侈品为什么这么贵?
      • 问题(找解释)知识,遇到问题,抛弃第一反应,去想想有什么方法论模型可以用

        • 看书遇到有趣的理论,先记下思考3个可以用该模型解决的问题。下次不要下意识反应,学会去翻一下以前的笔记,把问题补充到笔记里。
    • 3.做系统化训练

      • 刻意练习;一个月中,显示每天练习三段式,再提炼主题,然后积累结构
      • 我们的习惯,是高估几天的变化,而低估几个月的变化。
  • 汇总;如何具体到行动中;

  • 1.找专业人士了解领域的核心20%,先去学习20%

  • 2.在学习的过程中,思考各个知识点的应用场景,并记录下来,遇到问题再回去找

  • 3.能力提升是一个系统性过程,所以需要坚持至少1个月。

五、三大系统,让学习不靠意志力

  • 为什么我们如此难坚持

    • 意志力是有限的,并不是学习这件事情类到你,而是“坚持”
    • 移动互联网时代,诱惑越来越多
    • 威尔海姆。霍夫曼主持的一项研究表明;人们醒着的时候,把大约1/4的时间用来抵制欲望。
  • 意志力不够用,就用行为改变来学习。

    • 决定事情时起作用的大脑内部的两个系统;理性和感性。
  • 如何让我们坚持做一件事的三个关键因素;

    • 理性上;知道要学习(树立明确的目标)

      • 明确的目标是坚持学习的第一步
    • 感性上;愿意去学习(利用情绪冲动)

      • 截止日期的紧迫感
      • 比较产生的焦虑感
      • 鼓励带来的成就感
    • 情景上;制造适合学习的场景(创造学习环境)

      • 人是社会动物,我们会观察周围人的行为来调整自己的行为。
      • 如果可以利用环境,就不要用你的意志力来抵制欲望

六、三个建议,让你不做“定制化人才”

  • 1.调整主体,给自己定好发展方向
  • 2.提升能力,让自己成为横向可迁移的人才
  • 3.提升认知高度,让自己成为纵向可拓展的人才

源引感谢:

本文引用的内容,如有侵权请联系我删除,给您带来的不便我很抱歉。

最近看了《抉择》,虽说本身是一本企业管理的书,但是对人自身也是特别有指导意义的…

背景

由于某些客户现场以及我们公司自身的要求,产品上线之前都会有一轮的安全扫描,用AppScan等这类工具扫一扫,最近就处理了几个安全扫描的问题,虽说处理的比较原始但是还是需要记录一下,你晓得哇,因为比较折磨人。

工作原理

什么交XSS、SQL注入网上一大堆我就不出丑了哈,要解决这块问题那就先得搞清楚AppScan这类软件的工作原理。

AppScan 工作原理小结如下:

  • 通过爬行配置的整个 Web 应用,了解其结构找到接口等信息
  • 根据分析的结果,发送修改后的Request 进行攻击尝试(扫描规则库模拟XSS、SQL注入等操作)
  • 最后分析 Respone ,验证是否符合预期是否存在安全漏洞

所以由此看出处理XSS、SQL注入等问题只能在第二个和第三个环节出手。

处理姿势

处理这类问题我所知道的通常就3种姿势:

  1. 拦截

    触发了这类校验直接拦截掉并提示不让其做任何操作,简单粗暴但是不人性化。经常让人很懵逼。

  2. 替换

    把可触发这类校验的关键字全部替换为其它字符或者转换为字符串等。这种容易破坏原有的表达。

  3. 加密

    这是种欺骗扫描软件的方式,直接前后端约定加密方式,对所有的输入进行统一加密,后端再统一解密,这样扫描软件识别不了任何关键字。我同事就这样干过,虽然说性能上会有一点问题但是好在不用动任何代码。嗯,这种只能说骚操作。

实操

最后和架构师定的方式是通过filter+正则这种最原始最简单的方式来做,我们这是toB的运维系统所以让大家失望了没上高大上的安全策略。

输入流

需要先搞清楚为什么需要处理输入流,因为 reqeust.getInputStream 方法只能读取一次。我们可以大概捋一下是咋回事。

我们需要输入流所以需要调用reqest.getInputStream(),getInputStream返回值为ServletInputStream,所以我们先看看ServletInputStream。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public abstract class ServletInputStream extends InputStream {
protected ServletInputStream() {
}

public int readLine(byte[] b, int off, int len) throws IOException {
if (len <= 0) {
return 0;
} else {
int count = 0;

int c;
while((c = this.read()) != -1) {
b[off++] = (byte)c;
++count;
if (c == 10 || count == len) {
break;
}
}

return count > 0 ? count : -1;
}
}

public abstract boolean isFinished();

public abstract boolean isReady();

public abstract void setReadListener(ReadListener var1);
}

然后知道是继承自InputStream,所以我们先看InputStream,注意read和reset方法。

read方法告诉我们会从输入流一直读取下一个字节、如果以达到末尾侧返回-1。

reset告诉我们可以重置读取的位置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
public abstract class InputStream implements Closeable {

// MAX_SKIP_BUFFER_SIZE is used to determine the maximum buffer size to
// use when skipping.
private static final int MAX_SKIP_BUFFER_SIZE = 2048;

/**
* Reads the next byte of data from the input stream. The value byte is
* returned as an <code>int</code> in the range <code>0</code> to
* <code>255</code>. If no byte is available because the end of the stream
* has been reached, the value <code>-1</code> is returned. This method
* blocks until input data is available, the end of the stream is detected,
* or an exception is thrown.
*
* <p> A subclass must provide an implementation of this method.
*
* @return the next byte of data, or <code>-1</code> if the end of the
* stream is reached.
* @exception IOException if an I/O error occurs.
*/
public abstract int read() throws IOException;

/**
* Repositions this stream to the position at the time the
* <code>mark</code> method was last called on this input stream.
*
* <p> The general contract of <code>reset</code> is:
*
* <ul>
* <li> If the method <code>markSupported</code> returns
* <code>true</code>, then:
*
* <ul><li> If the method <code>mark</code> has not been called since
* the stream was created, or the number of bytes read from the stream
* since <code>mark</code> was last called is larger than the argument
* to <code>mark</code> at that last call, then an
* <code>IOException</code> might be thrown.
*
* <li> If such an <code>IOException</code> is not thrown, then the
* stream is reset to a state such that all the bytes read since the
* most recent call to <code>mark</code> (or since the start of the
* file, if <code>mark</code> has not been called) will be resupplied
* to subsequent callers of the <code>read</code> method, followed by
* any bytes that otherwise would have been the next input data as of
* the time of the call to <code>reset</code>. </ul>
*
* <li> If the method <code>markSupported</code> returns
* <code>false</code>, then:
*
* <ul><li> The call to <code>reset</code> may throw an
* <code>IOException</code>.
*
* <li> If an <code>IOException</code> is not thrown, then the stream
* is reset to a fixed state that depends on the particular type of the
* input stream and how it was created. The bytes that will be supplied
* to subsequent callers of the <code>read</code> method depend on the
* particular type of the input stream. </ul></ul>
*
* <p>The method <code>reset</code> for class <code>InputStream</code>
* does nothing except throw an <code>IOException</code>.
*
* @exception IOException if this stream has not been marked or if the
* mark has been invalidated.
* @see java.io.InputStream#mark(int)
* @see java.io.IOException
*/
public synchronized void reset() throws IOException {
throw new IOException("mark/reset not supported");
}

所以从上面可以得知ServletInputStream是没有重写r关键的reset方法,所以行为是与InputStream保持一致的即输入流读取一遍之后就没了后续就一直返回-1。

所以解决办法就是找到重写reset的方法的类,即就找到我们常用的ByteArrayInputStream也是继承自InputStream,但是其重写了reset等方法。

我们看下源码:

注意read里面的pos变量,它是标识现在读取的流的位置,所以如果我们想多次读取输入流,需要调用上面说的reset方法重置pos为0。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
public
class ByteArrayInputStream extends InputStream {
/**
* The currently marked position in the stream.
* ByteArrayInputStream objects are marked at position zero by
* default when constructed. They may be marked at another
* position within the buffer by the <code>mark()</code> method.
* The current buffer position is set to this point by the
* <code>reset()</code> method.
* <p>
* If no mark has been set, then the value of mark is the offset
* passed to the constructor (or 0 if the offset was not supplied).
*
* @since JDK1.1
*/
protected int mark = 0;

/**
* The index of the next character to read from the input stream buffer.
* This value should always be nonnegative
* and not larger than the value of <code>count</code>.
* The next byte to be read from the input stream buffer
* will be <code>buf[pos]</code>.
*/
protected int pos;
/**
* Reads the next byte of data from this input stream. The value
* byte is returned as an <code>int</code> in the range
* <code>0</code> to <code>255</code>. If no byte is available
* because the end of the stream has been reached, the value
* <code>-1</code> is returned.
* <p>
* This <code>read</code> method
* cannot block.
*
* @return the next byte of data, or <code>-1</code> if the end of the
* stream has been reached.
*/
public synchronized int read() {
return (pos < count) ? (buf[pos++] & 0xff) : -1;
}

/**
* Resets the buffer to the marked position. The marked position
* is 0 unless another position was marked or an offset was specified
* in the constructor.
*/
public synchronized void reset() {
pos = mark;
}

这些搞清楚之后就是看怎么能在到咱们的filter的时候得到的request是可以读取多次同时又不影响其它地方的读取(比如controller),刚好severlet.api提供了一个叫HttpServletRequestWrapper的东西,刚好提供一种包装(专业名词:装饰器模式)的手法让我们可以包装request请求对象使其可扩展其它能力。包装高富帅哪里都吃得开。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
/**
* @author Gamehu
* @date 2019/5/9 18:32
* @description sql注入问题,前置处理输入流,避免输入流获取一次以后失效导致系统异常
*/
public class xxxHttpServletRequestWrapper extends HttpServletRequestWrapper {
private static final Logger LOGGER = LoggerFactory.getLogger(SqlInjectHttpServletRequestWrapper.class);
/**
* 存储请求输入流
*/
private byte[] body;


public SqlInjectHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
try {
body = inputStreamToByte(request.getInputStream());
} catch (IOException e) {
throw RiilExceptionUtils.bizException(e, BaseWebErrorCode.SecurityConstant.ERROR, BaseWebErrorMsg.SecurityConstant.ERROR_MSG);
}
}

/**
* 流转 字节数组
*
* @param is
* @return
* @throws IOException
*/
private byte[] inputStreamToByte(InputStream is) throws IOException {
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int ch;
while ((ch = is.read(buffer)) != -1) {
byteStream.write(buffer, 0, ch);
}
byte[] data = byteStream.toByteArray();
byteStream.close();
return data;
}

@Override
public BufferedReader getReader() {
return new BufferedReader(new InputStreamReader(getInputStream()));
}

/**
* 重写方法用于多次获取流,防止读取用于校验过后,后面服务无法获取参数的情况
*
* @return
*/
@Override
public ServletInputStream getInputStream() {
final ByteArrayInputStream bais = new ByteArrayInputStream(body);
return new ServletInputStream() {

@Override
public boolean isFinished() {
return false;
}

@Override
public boolean isReady() {
return false;
}

@Override
public void setReadListener(ReadListener readListener) {
LOGGER.info("setReadListener");
}

@Override
public int read() {
return bais.read();
}
};


}

OK,到这儿输入流总算搞定了,nice,然后开始Filter上场了。

Filter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107

/**
* @author Gamehu
* @date 2018/12/20 15:18
* @description XSS、SQL注入校验
*/
@WebFilter(urlPatterns = "/*", filterName = "xxFilter")
public class xxFilter implements Filter {


@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
...
//安全扫描问题(sql注入、xss)处理,对参数进行校验
securityScanParamsValidate(filterChain, response, request);
}


/**
* 安全扫描问题(sql注入、xss)处理,对参数进行校验
*
* @param filterChain
* @param response
* @param request
* @throws IOException
* @throws ServletException
*/
private void securityScanParamsValidate(final FilterChain filterChain, final HttpServletResponse response, final HttpServletRequest request) throws IOException, ServletException {
final String paramsAndValues = SecurityScanUtil.extractPostRequestBody(request);
if (StringUtils.isEmpty(paramsAndValues)) {
filterChain.doFilter(request, response);
} else {
//根据参数是否能转换为json,执行不同的校验
parseParamAndValidate(filterChain, response, request, paramsAndValues);
}

}

private void parseParamAndValidate(final FilterChain filterChain, final HttpServletResponse response, final HttpServletRequest request, final String paramsAndValues) throws IOException, ServletException {
try {
final JSONObject paramsObj = JSONObject.parseObject(paramsAndValues);
if (paramsObj.size() == 0) {
filterChain.doFilter(request, response);
} else {
//对参数进行拆分校验,只校验每个参数值
jsonParamValidate(filterChain, response, request, paramsAndValues);
}

} catch (JSONException ex) {
LOGGER.error("isJSONValid,不是有效的JSON字符串,{}", ex.getMessage());
//参数不是合法地json格式则进行整句校验(不进行任何拆分)
notJsonParamValidate(filterChain, response, request, paramsAndValues);
}
}

/**
* 非json格式参数安全问题校验
*
* @param filterChain
* @param response
* @param request
* @param paramsAndValues
* @throws IOException
* @throws ServletException
*/
private void notJsonParamValidate(final FilterChain filterChain, final HttpServletResponse response, final HttpServletRequest request, final String paramsAndValues) throws IOException, ServletException {
final String uri = request.getRequestURI();
// sql注入校验
if (SecurityScanUtil.execSqlInjectValidate(uri, NO_KEY, paramsAndValues)) {
response.sendRedirect(SQL_INJECT_ERROR);
} else if (XssUtil.xssMatcher(uri, NO_KEY, paramsAndValues)) {
//xss校验
response.sendRedirect(XSS_ERROR);
} else {
filterChain.doFilter(request, response);
}
}

/**
* json格式参数安全问题校验(sql注入、xss)
*
* @param filterChain
* @param response
* @param request
* @param paramsAndValues
* @throws IOException
* @throws ServletException
*/
private void jsonParamValidate(final FilterChain filterChain, final HttpServletResponse response, final HttpServletRequest request, final String paramsAndValues) throws IOException, ServletException {
//防sql注入校验
if (SecurityScanUtil.sqlInjectValidate(request.getRequestURI(), paramsAndValues)) {
response.sendRedirect(SQL_INJECT_ERROR);
} else if (SecurityScanUtil.xssValidate(request.getRequestURI(), paramsAndValues)) {
//xss校验
response.sendRedirect(XSS_ERROR);
} else {
filterChain.doFilter(request, response);
}
}

@Override
public void destroy() {
LOGGER.info("destroy");
}


}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
/**
*
* @author Gamehu
* @description Xss和Sql注入检查 工具类
* @date 2019/5/10 9:54
*/
public class SecurityScanUtil {
private static final Logger LOGGER = LoggerFactory.getLogger(SecurityScanUtil.class);
private static final String GRAPHQL = "graphql";

private SecurityScanUtil() {
}

/**
* 单个参数的sql注入校验
*
* @param paramName
* @param value
* @return
*/
public static String sqlInjectionValidate(final HttpServletRequest request, final String paramName, final String value) {
if (StringUtils.isEmpty(value)) {
return null;
}
/*
* 防sql注入,如果存在抛出校验异常
*/
if (SqlInjectUtil.haveSqlInject(request.getRequestURI(), paramName, value)) {
return "sqlError";
}

return value;
}


/**
* 读取输入流中参数
*
* @param request
* @return
*/

public static String extractPostRequestBody(final HttpServletRequest request) {

final Scanner s;
try {
s = new Scanner(request.getInputStream(), "UTF-8").useDelimiter("\\A");
} catch (IOException e) {
throw RiilExceptionUtils.bizException(e, BaseWebErrorCode.SecurityConstant.INPUTSTREAM_ERROR, BaseWebErrorMsg.SecurityConstant.INPUTSTREAM_ERROR_MSG);
}
return s.hasNext() ? s.next() : "";

}


/**
* 效验sql注入问题
* <h3>SQL注入的几种方式:</h3>
* <pre>
* 1) 使用 ' or 语句,将查询条件扩大,实现破坏性查询(操作)
* 2) 使用 ; 将SQL分成两部分,在后面一部分实现破坏性操作
* 3) 使用注释,将后面的条件取消掉,将查询条件扩大,注意MySQL有三种注释的方法,都需要处理
*
* 为了简化处理,这里只考虑字符串类型参数注入情况(整型等其它类型在应用内部类型转换会失败,所以基本可以忽略)
* </pre>
*
* @return
* @throws IOException
*/
public static boolean sqlInjectValidate(final String uri, final String paramsAndValues) {
//获取参数列表以及参数值
final JSONObject paramsObj = JSONObject.parseObject(paramsAndValues);
final Set<String> keys = paramsObj.keySet();
return keys.stream().anyMatch(key -> haveSqlInjectCondition(uri, paramsObj, key));
}

/**
* 判断是否存在sql注入的表达式
*
* @param uri
* @param paramsObj
* @param key
* @return
*/
private static Boolean haveSqlInjectCondition(final String uri, final JSONObject paramsObj, final String key) {
//graphql 不进行校验
if (key.equalsIgnoreCase(GRAPHQL)) {
return false;
}
final String value = convertParamToString(paramsObj, key);
return SqlInjectUtil.haveSqlInject(uri, key, value);
}

/**
* 效验XSS问题
*
* @param uri
* @param paramsAndValues
* @return
*/
public static boolean xssValidate(final String uri, final String paramsAndValues) {
//获取参数列表以及参数值
final JSONObject paramsObj = JSONObject.parseObject(paramsAndValues);
final Set<String> keys = paramsObj.keySet();
return keys.stream().anyMatch(key -> haveXssCondition(uri, paramsObj, key));
}

/**
* 判断是否存在xss的表达式
*
* @param uri
* @param paramsObj
* @param key
* @return
*/
private static boolean haveXssCondition(final String uri, final JSONObject paramsObj, final String key) {
final String value = convertParamToString(paramsObj, key);
//判断是否存在xss攻击问题
return XssUtil.haveXss(value, key, uri);
}

/**
* 处理参数为字符串
*
* @param paramsObj
* @param key
* @return
*/
private static String convertParamToString(final JSONObject paramsObj, final String key) {
final Object obj = paramsObj.get(key);

String value = null;

if (obj instanceof JSONObject) {
value = ((JSONObject) obj).toJSONString();
}

if (obj instanceof JSONArray) {
value = ((JSONArray) obj).toJSONString();
}

if (obj instanceof String) {
value = (String) obj;
}
return value;
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63

/**
* @author Gamehu
* @date 2019/9/26 12:12
* @description XSS校验的工具类
*/
public class XssUtil {
private static final Logger LOGGER = LoggerFactory.getLogger(XssUtil.class);
private static final String GRAPHQL = "graphql";
private static Pattern[] patterns = new Pattern[]{
// Script fragments
Pattern.compile("<script>(.*?)</script>", Pattern.CASE_INSENSITIVE),
// src='...'
Pattern.compile("src[\r\n]*=[\r\n]*\\\'(.*?)\\\'", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
Pattern.compile("src[\r\n]*=[\r\n]*\\\"(.*?)\\\"", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
// lonely script tags
Pattern.compile("</script>", Pattern.CASE_INSENSITIVE),
Pattern.compile("<script(.*?)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
// eval(...)
Pattern.compile("eval\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
// expression(...)
Pattern.compile("expression\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
// javascript:...
Pattern.compile("javascript:", Pattern.CASE_INSENSITIVE),
// vbscript:...
Pattern.compile("vbscript:", Pattern.CASE_INSENSITIVE),
// onload(...)=...
Pattern.compile("onload(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL)
};


/**
* 判断是否存在xss攻击
*
* @param value
* @param key
* @param uri
* @return true表示存在,false表示不存在
*/
public static Boolean haveXss(final String value, final String key, final String uri) {
if (key.equalsIgnoreCase(GRAPHQL)) {
return false;
}
return xssMatcher(value, key, uri);
}

public static boolean xssMatcher(final String value, final String key, final String uri) {
if (StringUtils.isNotBlank(value)) {
Matcher matcher;
for (Pattern pattern : patterns) {
matcher = pattern.matcher(value);
// 匹配
if (matcher.find()) {
LOGGER.error("存在xss风险,URI:{},参数:{},参数值:{}", uri, key, value);
return true;
}
}

}
return false;
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

/**
* @author Gamehu
* @date 2019/9/26 12:12
* @description SQL注入校验的工具类
*/
public class SqlInjectUtil {
/**
* SQL语法检查正则:只检查一个关键字可能存在误判情况,这里要求必须符合两个关键字(有先后顺序)才算匹配
* 第一组关键字
*/
final static String sqlInjectGroup = "select|update|and|or|delete|insert|trancate|char|into|substr|ascii|declare|exec|count|master|drop|execute";

/**
* 构造SQL语法检查正则
* (?i)忽略字母的大小写,\s.*空白+字符
*/
final static Pattern sqlSyntaxPattern = Pattern.compile("(?i)(.*)\\b(" + sqlInjectGroup + " )\\b\\s.*", Pattern.CASE_INSENSITIVE);


/**
* 读取输入流中参数
*
* @param request
* @return
*/

public static String extractPostRequestBody(final HttpServletRequest request) {

final Scanner s;
try {
s = new Scanner(request.getInputStream(), "UTF-8").useDelimiter("\\A");
} catch (IOException e) {
throw RiilExceptionUtils.bizException(e, BaseWebErrorCode.SecurityConstant.INPUTSTREAM_ERROR, BaseWebErrorMsg.SecurityConstant.INPUTSTREAM_ERROR_MSG);
}
return s.hasNext() ? s.next() : "";

}

/**
* 执行SQL注入校验
*
* @param uri
* @param key
* @param oldValue
* @return
*/
public static boolean haveSqlInject(final String uri, final String key, final String oldValue) {
if (StringUtils.isNotBlank(oldValue)) {
//统一转为小写
final String newValue = oldValue.toLowerCase();
final String logStr = "存在sql注入风险,URL:{},参数:{},参数值:{}";
// 检查是否包含SQL注入敏感字符
if (sqlSyntaxPattern.matcher(newValue).find()) {
LOGGER.error(logStr, uri, key, newValue);
return true;
}
}
return false;
}

}

因为我们用了graphql,有些地方还用了dsl,所以正则是魔鬼,我写崩溃了差点,当然如果有更好的方法请告诉我,万分感谢。

长出一口气…..

本文引用的内容,如有侵权请联系我删除,给您带来的不便我很抱歉。

高难度沟通发生的三个场景

矛盾、争取、推进

近段时间刚好,做的分享和听的分享较多。刚好缘分就是那么奇妙,在一个网课平台刚好看到了这个网课《如何提高Presentation的展现能力》,在此做个记录。

图1所阐述的观点,是我个人觉得做得最契合的。确实我一直认为,Presentation别弄太多文字类或者花哨的东西,PPT应该是辅助我们说明白一个事情,所以主次需要分清。

图2所说几个点

  • 底稿我觉得如果是很正式或者很重要的Presentation是个很好的减少风险的点。

  • 另外关于互动,这点是很重要的,不管是眼神还是肢体还是语言,他能让讲解人和听众建立联系,如果没有互动,那就感觉像是下命令了,你们只管听我只管讲,不能有异议这样的场景特别糟糕。

  • 时间管理特别重要,我特别厌烦那种拖沓的,慢条斯理的Presentation,让氛围很疲惫,这种效果很差,这点我也需要改进,虽然我很注意时间控制,但是也没有做到掐表的程度,但是我认为有些情况是可以掐表,比如做分享。

图3是我最没有底气的点,Presentation事后的修正和反思做得比较少,特别是修正,要想整个Presentation比较有质量,确实这块是不可或缺的,尽量不因此留下遗憾。

Presentation:我觉得可解释为:具有分享、议题、同步等性质的会议。

图片摘自:

嗯,跟前端暧昧的时间还是挺长了,是时候展现真正的技术了。

常在写代码哪有不bug的道理,那对于前端朋友来讲chrome的工具栏基本上能满足大多数场景下的bug排查,对于奉行假如你暂时不够牛逼,那就善用工具的我来说,我心荡漾啊。必须记录一下,当然chrome提供的工具太多了,今天暂且主要聊聊Sources,也是我使用频率Top 2,结合一些网上的一些说明加自身的实践来说一说。

不用再于数字不好看这些细节,我们走的是放荡不羁的路线,咱们挨个说啊。

数字 表头
1 点击该箭头,移动鼠标到页面上定位到页面元素,跳转到Elements 工具栏。
2 用于模拟移动设备上的效果。
3 必用的模块,已加载的全部资源,以域名划分文件夹,调试时从这儿下手找源码,当然我通常直接快捷键Ctrl+P定位文件。
4、5 Filesystem & Overrides 可以加载本地文件夹,把Chrome当成IDE用。
6 Content scripts 扩展工具的脚本,比如百度翻译插件等
7 Snippets 代码片段,不会因为刷新丢失,使用:添加=>保存(ctrl+s)=>运行(Run)=>不用则移除(Remove)
8 源码面板,在此处进行打断点、修改端点等操作
9 调试的快捷键面板
10 变量监察:添加个变量后会一直监察这个变量的值,当前作用域无值时显示< not availble >
11 Call Stack 函数调用栈,会列出断点的调用堆栈列表。
12 Scope 断点所在作用域列表,级别划分如下:
  • Local 当前作用域 展示作用域下的变量
  • Closure (x) 闭包作用域,x是函数名称
  • Script 标签作用域
  • Global 全局作用域Window
13 Breakpoints 源码的断点列表。
14 XHR/fetch Breakpoints 请求断点:ajax和fetch请求都可以在这里打断点并在Call Stack显示调用栈,很方便追踪。
15 DOM Breakpoints 这里列出html的断点。
16 Global Listeners 全局监听器:指的是绑定在 window 对象上的事件。
17 Event Listeners Breakpoints 所有事件的断点:勾选指定类型,比如Mouse/click,则所有的click事件都会被断住。

markdown搞出这个表格太费劲,anyway看着舒服就好,下面聊聊对应上面表格中的一些具体的使用场景。

  • Filesystem Chrome式的IDE,可以编辑各种文件并且在当前页就可以实时刷新看到效果,如果写单个模块时蛮有用的,比较快。修改后ctrl+s保存,修改的是本地文件,刷新可看到效果。
  • Overrides 覆盖网络请求的资源,即html、js、css、图片等资源,注意一定是同域名同路径同名的文件才能产生覆盖效果。勾选,Enable Local Overrides,修改文件后ctrl+s保存,修改的是Save as Overrides到本地的文件,刷新可看到效果。

  • Snippets,也是我使用比较多的功能,以前不知道的时候都是找网上现场的js编辑器,但是受网络和维护的影响,有些时候不好用,而且很多还要区分ES5、ES6,自从有了Snippets,随便写各种代码片段超级好用。 但是要注意变量的作用域问题,所以最好用IIFE方式写代码,避免出现错误。

源码面板

  • 这也是调试的时候使用频率超级高的区域,ctrl+p定位到文件,行号处右键出现对断点操作的一些选项,分新增和编辑两类。
  • Add conditional breakpoint/edit breakpoint ,添加/修改带条件的断点,比如写a===”a”,则表示当a等于”a”时才触发断点,如下图。当条件表达式为真时,触发断点(条件性行断点的颜色为橙色)
  • Blackbox Script,黑盒脚本,很多时候是要引用第三方库或框架的,当我们调试时,调试的对象应该是我们自己写的代码,但很多时候,我们经常在焦灼地进行下一步下一步时,突然代码跳到了第三方库或框架的源码上去,多数情况下我们不会关注这些地方的内容,但是它就要跳过去,这种是比较蛋疼的。黑盒脚本就是用来解决这个问题的,它能够把一个脚本文件标记为 “Blackbox Script”,那么我们就永远不可能进入这个文件内部,这个文件对我们来讲就是一个黑盒子。为什么要强调“永远”呢?因为不仅普通的断点不能访问这个被标记了的脚本,其他的,比如说 DOM 断点、事件断点等等都无法访问那个脚本文件内部。

  • 调试面板:Pause on exceptions,在发生异常的地方停顿

Watch面板

  • 用于监视变量的值。

点击1处,将打开一个内联输入框,您可以在输入框中输入要监视的变量名称。输入完毕,按Enter键,即可将其添加到列表中。监视器将显示添加时变量的当前值。如果变量未设置或找不到,值将显示为

点击2手动刷新变量。注:监视列表不是变量的实时视图,除非逐步执行。当使用断点逐步执行时,监视列表中的值将自动更新

点击3,删除变量。

Call stack

代码暂停时,可以在Call Stack窗口查看当前的调用栈。展示了代码到暂停处的完整执行路径,这让我们能够深入代码去找出导致错误的原因。最后调用函数在最顶上,所以最好别用匿名函数,不利于调用栈查看。

Scope

作用域:显示断点所在的作用域,级别划分如下:

Local 当前作用域 展开作用域下的变量
Closure (x) 闭包作用域,x是函数名称
Script 标签作用域
Global 全局作用域Window

DOM Breakpoints

当改变一个节点或者其子元素时,可以设置一个DOM断点:

  1. 点击Elements面板

  2. 找到想要设置断点的元素

  3. 在此元素上右键

  4. Break on –> Subtree modifications / Attribute modifications / Node removal

    Subtree modifications(子树修改):当前选中的元素,删除、增加其子代或者改变其子代的内容。修改子元素的属性或者当前选中元素有任何改变都不会触发此类型断点
    Attributes modifications(属性修改):当前选中的元素,增加、删除其属性,或者修改某个属性值
    Node Removal(节点移除):移除当前选中的元素

XHR/Fetch Breakpoints

当XHR的请求URL包含某一特定的字符串时,可以暂停调试代码。DevTools会在XHR调用send()那行代码的地方暂停。

  1. 点击Sources面板
  2. 展开XHR Breakpoints小窗口
  3. 点击“增加断点(Add breakpoint)”
  4. 输入一个字符串,只要在某个XHR的请求URL中包含此字符串, 会进入断点(暂停),如下图。

Event Listeners Breakpoints

这个断点类型也算是比较常用的一个了,特别是当我们调试别人的代码时,触发某个事件,想找到对应的代码。事件类型可以是很具体的,比如click事件,也可以是某一类别的事件,比如“鼠标事件”。

  1. 点击Sources面板
  2. 展开Event Listener Breakpoints小窗口
  3. 勾选某一类别的事件或者是某一具体的事件

PS:

感谢:

本文引用的内容,如有侵权请联系我删除,给您带来的不便我很抱歉。

今天看到一篇文章,是以我媳妇儿的男神马云老师为引得文章。

所有为了能更完美的适配我媳妇儿的诉求,当然我就毫不犹豫的要点进去的看看。

我心甚慰啊,是这两天引发我思考最多的文章,特此记录一下。

文章指出底层系统定义:那些驱动你的核心动力。

体现在两个方面:大局观和是非观。

是非观决定你能走多久。什么事能做什么事不能做,自己心里衡量。有界限。

大局观决定你能走多远。你想进步你的格局就要大于你的现状。

所以前者指引方向,后者决定边界。

所以当你想做什么的时候,先自省一下,自己的底层系统,看有没有bug。

其中大局观是我感慨最多也是我认为自己最需要严肃对待的。

虽然我这两年都在有意识的往这方面努力,但是还远远不够。

记录下我粗糙的认识

我认为的大局观,首先需要对抗的就是,老守着自己的一亩三分地,事不关己高高挂起,满足于现状的状态(这也是我在正在经历的阶段),需要跳脱出来,换角度,纵向、横向的看自己看周围看世界。

说起来有点虚,我一开始看别人动不动用跳脱、升华、灵魂这类词语我就特别不屑,总觉得的是吹牛x。但是亲测真的有效,很多时候做某件事的时候我就强迫自己,重新审视一下要做的事。

那怎么才能重新审视呢,那就涉及到要需要换角色换角度了,那怎么才能换角色换角度呢,这个时候就会突然在头脑中会出现,自己扮演产品经理、研发总监(公司副总)、总经理的角色,另外还会出现一个专门发出质疑的“自己”。这时候你就会萌发很多很多想法,这时候你会发现你考虑事项的方式以及处理事项的方式往往会和你一开始你想的有出入(当然这里肯定有一个边界,那就是你得从你的现状出发),这种出入不见得一定优于之前的想法,但是它肯定会带来附加效果,这种附加效果有可能会来的快也可能来得晚,有可能好有可能坏,但是正因为这样我们才能不断修正自己,我想这种修正应该会让我向大局观进一步。

最近在看一本书《系统之美》,看起来有些艰涩,但是真的很受用,我觉得其中有句话就很符合我对大局观的理解

重塑系统,发现更大的世界

对于怎么才叫有大局观,我其实也没摸到精确的定义,但是这不妨碍我想得到她。人神奇的地方不就是能不断的折腾吗。能捏碎也能重塑。

最后

我觉得作为程序员,别顽固(坚守哪个语言第一、接受不了改变…)、别看谁都不顺眼(你看那说话的SB、你看那写代码的SB、你看那群里发图的SB….)、别老想着对抗(产品、ucd、测试、运维….,感觉他么的一个公司全是你的敌人),我们应该多想想如果我保持现状到底跟自己的职业生涯、跟同事、跟领导、跟公司能带来什么。

我们是不是得抽时间找找自己?

本文引用的内容,如有侵权请联系我删除,给您带来的不便我很抱歉。

当你不够牛逼时,那就善用工具

我简单整理了一下我最近比较常用的工具,也会摘一些做一些分析,多偏向于前端,因为最近前端写得多。

chrome devtools