leadscloud

Google SEO|外贸营销推广

今天看完了 bbc的纪录片 《数学的故事》,非常有意思,虽然无法理解其中的很多数学知识,但看过之后,你真的会觉得数学是一切知识的基础,包括我们现代社会所用到的一切科技都与他有关系。包括我们的互联网,都是构建在数学大夏之下。

而其中最有意思的就是“不完备定理”, 纪录片中说的是,总是存在数字的真命题,但你无法证明它有真假。 它举了一个例子,比如一个题目: “引命题无法证明 ”。 如果这命题是假的,这个命题是可证明的,也就意味着它是真命题,这就产生了矛盾。那也就是说,这个命题肯定是真的。这是一个真命题,但你却无法证明。

哥德尔之后也受精神分裂的困扰,这样的数学,我是无法理解的,至少我只是按自己的想法去理解,让我有点觉得上帝是存在的,这个命题是不是也是无法证明的。

另外,里面提到的数学都是人类在生活实际中产生的,才知道我们从小所学的数学都是人类几千年来因为使用才产生的,每个数学在早期产生都是有现实意义的,无穷数最开始从印度产生与印度的社会及虚无有关系的,里面讲到了无穷的概念,虚数,以及拓扑,看过之后,你会对数学有更深的认识。

数学还是非常有意思的。

http://zh.wikipedia.org/wiki/%E5%93%A5%E5%BE%B7%E5%B0%94%E4%B8%8D%E5%AE%8C%E5%A4%87%E5%AE%9A%E7%90%86
http://zh.wikipedia.org/wiki/%E5%BA%9E%E5%8A%A0%E8%8E%B1%E7%8C%9C%E6%83%B3 
http://zh.wikipedia.org/wiki/%E6%A0%BC%E5%A5%A5%E5%B0%94%E6%A0%BC%C2%B7%E5%BA%B7%E6%89%98%E5%B0%94
http://zh.wikipedia.org/wiki/%E5%B8%8C%E5%B0%94%E4%BC%AF%E7%89%B9%E7%9A%8423%E4%B8%AA%E9%97%AE%E9%A2%98

2014年7月4日,我从百度离职了。

这是第一次,我不是因为和老板闹翻而离职;

这是第一次,我带着晋升的喜悦而离职;

这是第一次,我带着满满的收获而离职。

我曾经认为,我永远不会成为一个好员工,因为我太独、太挑剔、不喜欢听话的好孩子、而且讨厌一切想要改变我的人。但是三年过去,我改变了不少,我必须承认,所谓“进步”的过程,就是被认可的过程,也是被“驯化”的过程。

所谓“驯化”,就是了解规则、遵守规则、利用规则的过程。我并非被某些人“驯化”,而是被社会与职场的规律驯化。我曾经鄙视这个过程,但今天看来,作为一个资质平庸的人,如果你想在这个社会里做成点儿什么,“被驯化”是不可避免的。

我也曾自诩“卓尔不群”,又受了老罗“彪悍的人生不需要解释”的“蛊惑”。但在现实中,这个路子不一定行得通。你不得不向很多人解释、用他们(而不是自己)喜欢的方式解释,因为只有得到他们的认可和支持,你才能继续工作下去。如果你是一个资质平庸的人,你不得不这样做,美剧《犯罪心理》中有一句话:“凡按自己的方式追求理想者,无不树敌。”

树敌多了,你就死了。

现在,我不敢说自己是个“好员工”,我只是觉得我是个比曾经的自己更好的员工。在离职的时候,我打算把自己这几年的职场心得总结一下,算是给自己的一个礼物。

我是一个资质平庸的人,以下这些心得只适用于愚钝且资质平庸的我,对于才华横溢的天才们并不适用。

一、你有“同理心”吗?

什么叫“同理心”?

说复杂点儿,同理心就是站在当事人的角度和位置上,客观地理解当事人的内心感受,且把这种理解传达给当事人的一种沟通交流方式。

说简单点儿,同理心就是“己所不欲,勿施于人”。将心比心,也就是设身处地去感受、去体谅他人。

说白了,同理心就是“情商”。

具体点说:

同理心就是,领导交办一项工作,你要读懂他的目的、看清他的用意。我经常遇到这样的情况:给团队成员安排工作时,一再询问“我说明白了吗”“有没有问题”,再三确认后,提交上来的东西仍然答非所问。所以我在接受任务时,总会向领导确认:你想要的是什么?你的目的是什么?了解这个以后,就可以站在他的角度,有效的帮他解决问题。

同理心就是,在激励员工时,点准他们的“兴奋点”,不揭“伤疤”。每个人都有认真工作的理由,家庭富裕的为了证明自己的能力,家境贫寒的为了改善自己的生活,吊儿郎当的爱面子怕丢工作。了解不同人的不同心理需求,才能调动大家的积极性。若是不问青红皂白,拿着鞭子大喊加油,只能是徒劳无功。

同理心就是,在与他人合作时,了解对方的需求和心理,潜移默化的说服对方,双方为了同一个目标而努力。想用强势压服别人,通常不好使。

二、听话,出活;

7年前,我和北京交通台的潘久阳聊天,他说“什么叫好员工啊,好员工特简单,就四个字:听话、出活”。这话我一直记着,这是至理名言。

什么叫“听话”?有句老话叫“干活不由东,累死也无功”,谁是“东”啊?你的直属领导就是“东”,大部分时候,听他的话准没错儿。

有朋友说:我有能力,我比领导水平高,我就不听领导的!咱先不说到底谁水平高——既然他能当你领导,肯定有比你强的地方——咱就说水平和能力这事儿,什么叫“有能力”啊?领导用你,你就有能力。不用你,甭管您有再大的能力,都是白费。

根据我的经验,一般来说,领导都比你水平高,起码在一点上是这样:他比你信息更全面、判断的更准确。因为领导更容易接触到更高层,更了解更高层的意图,他知道的你不知道,你在自己的角度上认为“这么做对”,但领导在更高的层面,并不一定这么看。

还有朋友说我领导就是瞎指挥,明摆着不对,我干嘛要听他的?这是另外一个问题,咱们最后一条会谈到,如果你觉得现在的环境无法进步,就可以考虑离职了。

什么叫“出活”?就是领导给你的工作,你得按时完成并且汇报总结。如果这个工作要持续较长时间,那么你需要阶段性的给领导反馈。我们经常犯一个错误,领导安排的工作,他不问你也不说,黑不提白不提这事儿就算过去了。

过去了?哪儿那么容易啊!领导都记着呢,你等他问你的时候——“诶小陈,上次安排你做的那事儿怎么样了?”——他就已经在心里给你写上了标签:“不靠谱”。

一个“不靠谱”需要用十个“靠谱”来扭转,两个“不靠谱”就很难转变印象,三个“不靠谱”你就没有机会了。

“出活”还有一层含义,就是“超预期”。这个咱们在下一点聊。

三、要想人前显贵,必须背地里受罪;

在公司里上班,大家的智商都差不多,谁也不比谁强多少,拼的都是努力和用心的程度。你下功夫了,就比别人做得好。哦,本来就不比别人聪明,别人下班你也下班、别人玩儿你也玩儿、别人搞对象你也泡马子,你凭什么比别人干得好?

“要想人前显贵,必须背地里受罪”的道理并不难懂。就是真到受苦的时候就含糊了,有的人会说,我年纪轻轻的为什么不好好享受生活啊?这种想法很普遍,这本是一个价值观的问题,没什么可说的,一个人想怎么生活都对。但是有一些朋友是在追求理想和享受生活中纠结的,和这些朋友,是可以聊的。

马云曾经说过:我们追求的应是人生的大平衡,而不是一时一日的小平衡(大意如此)。新东方也有一句话说:怕吃苦吃苦一辈子,不怕苦吃苦半辈子。两句话大意相同,值得深思。

一件工作,你用心想了做了,领导一看就知道,你想糊弄,也是一看就知道,这个没侥幸。领导在判断这个问题的时候,标准很简单:我想到的,你都没想到,肯定没用心;我想到的,你想到了一部分,用心不够;我没想到的,你想到了,这是用心了——这就是“超预期”。如果你每次都能给你的老板一个超预期的结果,那你无疑就是一个好员工。

四、能忍多大事儿,就能成多大事儿;

讲一个笑话:

在电梯里,领导放了个屁,回头问秘书,谁放的?秘书忙答道:“不是我!”领导不说话,这事儿过去了。不久,秘书被调离,领导在谈起调离原因时说道:“屁大的委屈都受不了,还能做的了啥?”

在工作上想受到领导的赏识和重用,除了要有过硬的工作能力外,更重要的,要有足够的涵养(抗压力或者回血能力)。能受多大委屈,才能成多大事儿,这是一定的。为了考察你的“抗压力”,领导有时会故意试你,你可一定要经得住考验。

我自己也经历过类似的事情:

有一天加班,晚上2点钟到家,收到老板的一封邮件,批评我工作不到位。我收到邮件后就很崩溃,还很委屈。于是当即奋笔疾书,回邮件!解释我是如何工作的,我做的如何有道理,我做的如何有效果……写了2000多字。

写完了,我好像冷静了一些,我就琢磨一个事儿:如果我是老板,我对一个员工工作不满意,于是我给他写了封邮件批评他,我想看到的是他洋洋洒洒的解释和辩解吗?显然不是啊。然后我就突然明白了,于是我把那2000多字都删了,简单回复了一句话,大意是:我会反思工作的问题,然后尽快整改。

两个月后我晋升了。在我的晋升仪式上,我对我老板说起这件事,他对我说,我知道你很委屈,我就是想看看你在面对委屈和压力时,会有怎样的反应,这体现了一个人的成熟程度。

多说一句,人们会感叹“钱难赚,屎难吃”,人人都想“站着把钱赚了”,我更相信他跪着的时候你没看见。我们总是强调“尊严”,比尔盖茨说过一句话:“没有人会在乎你的尊严,你只能在自我感觉良好之前取得尽可能多成就。”

对于比尔盖茨这样的天才姑且如此,况且我这样资质平庸的碌碌之辈呢?

五、总躲着领导,你就危险了;

不少人躲着领导,尽量少跟领导说话、绕着领导走。因为跟领导近了事儿就多,不跟领导多接触,事儿少,多清闲。这是“一叶障目,不见泰山”。

如果你想在工作上取得一些成绩,我建议还是应该主动的多和领导沟通。领导在平时开会时说的多是大面儿上的话,真话、有用的话、有价值的话不一定说。这并不是他不想说,而是没机会说。

有心的员工会随时抽时间和领导沟通、增加私人交流的机会:一起吃饭、一起抽烟、一起上下班、甚至一起打球K歌……通过这样的机会,你可以了解领导对于你的看法、对于工作的观点,这些都有益于你调整自己的工作的方式。

有朋友担心这样做会引起领导反感,其实完全不会,领导们多是孤独的,如果他发现有一个员工虚心向他请教、积极分享工作的思考,他是非常高兴的。

有朋友说,我不想那么累,我就想混混日子。即便是这样,你最好也主动和领导沟通、主动汇报。你追着他,你是主动的一方,其实你不累;等到他追你的时候,你就被动了,最终就累死了。

老罗曾经讲过一个故事,说你进入单位,见到老板就低头过去、不理他,他当然也不理你。等到年终考核、或者裁员的时候,老板隐约记得有你这么个人,但不知道你的名字、更不知道你做了什么。老板会想:这是你的错,不是我的错。不开除你开除谁?

老板也是人,大家用人类的方式沟通,一切会变得简单很多。

六、帮助别人千万别吝啬;

马云曾经说,成功就是成就自己帮助别人。这话没错。

如果你在一家公司工作,你发现你的工作不用任何人协助就能自己独立完成,那你多半是个打杂的。相反,你的工作需要越多人协作,就越复杂、越高级。在实际工作中我发现,我处在一个协作关系网中,如果没有别人的帮助,我就无法工作下去。

当你正在忙于某项工作时,有同事来向你“求助”,很多时候我们会很直接、甚至粗暴的拒绝,殊不知这样做正在给你今后的工作种下麻烦的种子。风水轮流转,在一家公司里,大家的工作互相交叉的几率很大,说不定你会用上谁,这些人脉关系需要平时去维护。今天你帮助了人家,说不定明天对方就会成为你的救命稻草,这非常可能。

有一天我正在疲于应付一个项目总结,这时有个其他部门的同事来找我聊合作的事儿,我并不认识他,我耐心的和他介绍了情况,并且真的形成了几次愉快的合作,半年后,我的晋升答辩会上,我发现他是我的答辩委员……

七、目标再目标,量化再量化;

没有目标的,都不叫工作;没有量化的,都不叫目标。

在接受一项工作时,先问目标是什么;在布置一项工作时,先交代目标是什么。这个不说清楚,都是扯淡。

不想成为蒙着眼睛拉磨的驴?那么除了清楚的知道自己的目标外,还得知道你的部门、你的公司的目标,最关键的,你需要知道,你的工作在总体目标中处在什么地位、扮演什么角色。如果你发现,你工作的目标和总体目标关系很小、甚至没有关系,那么你就很容易被拿掉。

辞退员工,或给员工绩效打分“不合格”是很令人头疼的,但其实这事儿并不难。关键就在于事先和每个员工一起制定量化的工作目标,并且随时提醒员工,他的工作是否达到了要求。没有达到量化指标,辞退或“不合格”是令所当然事儿,在数据面前,再矫情的人也无话可说。相反,如果谈感觉、聊希望,这事儿就没法办了。

八、找到解决问题的办法是我的义务;

领导安排的工作,不能说“我做不了”、“我做不到”。

公司请我们来工作,是为了解决问题的,如果不能解决问题,我们就没有价值。工作推进中遇到困难,无法继续进行,这是很正常的事儿,我们需要做的是主动寻找答案和办法,哪怕你的办法不妥,那么就去问,但无论如何不能对你的领导说,我不会。

前天,我在公司里听见隔壁团队的领导安排同事定一个会议室,有公司工作经验的人都知道,会议室是很难订到的,弄不好还需要“托关系,走后门”。这个小同学可能是没有订到,于是和他的领导说“我没订到”,他的领导直接就急了,说:“那怎么办?需要我来订吗?”

这位领导发火是有道理的,这位小同学在发现自己订不到会议室后,应该做的是自己想办法解决问题——最简单的就是向老同事咨询。

解决问题的能力是员工最关键的能力,没有之一。在工作中遇到困难特别正常,在这时,我们有一项义务,就是找到解决问题的办法。

九、尽量不说“不是我,我没有”;

绝大多数人在面对批评的时候,本能反应都是推卸责任,此时的口头禅就是“不是我”、“没有我”。我总觉得,很多时候,越成熟的人,就越少用本能反应面对问题,因为他们有更强的自控力。

尽量不说“不是我”、“没有我”这样的话,因为这些话毫无作用,领导听惯了这样的推卸之词,丝毫不会为之所动。此时如果能够主动承担责任,反而体现了一种担

当。即便真是被冤枉了,当场辩解往往也不是最明智的选择,可以先保持沉默,私下找机会和领导进行沟通。这个详见第三条。

十、“言多必失”死得惨;

在公司里,少说闲话,不说是非话,不做是非人。

你就相信一点:你说的每句话,你的老板都会知道。好话可能不一定,坏话则是一定的。

还是做个正直的人吧,这样最简单,也受益最大。正直人的原则是:批评当面说,赞美背后讲。

十一、知道什么时候离开。

好多同事和朋友和我聊过离职的话题,我对朋友们的建议是,如果你因为觉得工作不爽,那就别离职,因为甭管到哪里,都会不爽:老板不喜欢、同事不可爱、工作太劳累、关系太复杂……我以我在多家大公司工作的经历担保:几乎所有我工作过的公司,令人不爽的事儿都是一样的。

那么什么时候离开呢?我想,有两种情况:

1、在这家公司,你已经没有上升的空间、无法学习到更多的东西了;

2、在这家公司,你已学到足够的知识,可以在新领域或新平台上一展身手了。

(完)

原文:http://meroa.com/baidu-staff-summary/

安装sendmail并启动它

1
2
yum install sendmail
service sendmail start

设置sendmail开机自动运行

1
2
yum install chkconfig
chkconfig sendmail on

测试邮件发送功能

1
echo "This is test mail" | mail -s 'Test mail' xxxxx@qq.com

如果提示 mail: command not found, 那么就是没有安装mail命令,此时需要安装mail命令:

1
yum install mailx -y

安装过mail后就可以发送了,我测试了下,发送到我的QQ邮箱中是没有问题,并且不会识别为垃圾邮件。

如果想配置php的mail发送函数,按以下设置:

修改下php.ini的配置,调用sendmail功能

1
vim /usr/local/php/etc/php.ini

找到有关sendmail_path的那一行,去掉行首注释,并改成如下的样子:

1
sendmail_path = /usr/sbin/sendmail -t -i

20140624143525
本文讲述如何免费申请SSL证书,并搭建https网站,由于服务器是NGINX,顺便会介绍如何安装SPDY协议。

StartSSL介绍

StartSSL是一家CA机构,它的根证书很久之前就被一些具有开源背景的浏览器支持(Firefox浏览器、谷歌Chrome浏览器、苹果Safari浏览器等)。
在今年9月份,StartSSL竟然搞定了微软:微软在升级补丁中,更新了通过Windows根证书认证程序(Windows Root Certificate Program)的厂商清单,并首次将StartCom公司列入了该认证清单,这是微软首次将提供免费数字验证技术的厂商加入根证书认证列表中。现在,在Windows 7或安装了升级补丁的Windows Vista或Windows XP操作系统中,系统会完全信任由StartCom这类免费数字认证机构认证的数字证书,从而使StartSSL也得到了IE浏览器的支持。

StartSSL申请注意事项

(1)需要一个域名,并开通域名邮箱,邮箱前缀为:webmaster这样的信息,一定要开通一个webmaster@yourdomainname.com这样的域名,这个会用来验证你的域名;
(2)申请时一定要填写完整正确的信息,否则无法通过申请,我就是因为第一次填写的地址信息不全,没有通过,一般添写正确的地址很快就会通过的;
(3)打开网站 在control panel / sign-up 注意填写正确资料。收到邮件后复制验证码。然后可以生成一个证书,注意,startssl.com不是以用户名、密码来验证用户的,是用证书来验证用户的。所以生成证书后(火狐会导入证书),注意备份证书。丢失证书后只能重新注册。
(4)登录后还要验证域名才能为该域名生成SSL证书,可以选择在whois里的邮箱、hostmaster@domain、postmaster@domain或者webmaster@domain
(5)然后就可以在Certificates wizard里就可以申请SSL证书了。
(6)有效期一年(到期前会收到邮件通知续期)。

申请流程

所有的资料都最好使用正确的。因为注册SSL是一件很严肃的事情。还有就是如果你的IP地址是在大陆,你输入香港也是会被拒绝的。而且你的地址也是也是要详细的。按照表单写完以后点击Continue按钮。然后你填写的邮箱会收到一个验证码。 上面说大概需要等6个小时收到通知,其实一般一两分钟就会出结果

打开你的邮箱,把验证码输入到你的浏览器Code的框里,然后继续。

通过后,会收到通过验证的邮件,然后给你一个URL,输入到浏览器中进行下一步安装证书。如果弹出的窗口依然还让你输入Code,那则输入邮件下面链接的Code。

点击Continue,接下来你的浏览器开始安装私钥,相当于建立用户名密码

然后密钥安装成功以后提示你开始安装证书。

证书安装完毕以后会祝贺你一下。点击完成。 这时给你会收到邮件说你安装好啦,可以使用了。

在Validations Wizard选择里验证你的域名。按照提示操作就行了,它会扫描你的网站上的邮箱,然后列出来,会给你的邮箱发一封信,所以你一定要有一个企业邮箱来收信的。域名验证成功后,接下来申请域名SSL证书。

点击Certificates Wizard ,选择下拉菜单中的Web Server SSL/TSL Certificate

然后进入下一步他会问你验证方式,这一步如果你跳过需要在VPS上设置,具体可以见网站:http://blog.nicky1605.com/the-free-ssl-configuration-startssl-on-nginx.html

如果没有跳过,你必须设置密码,不少于10位的。然后点击下一步生成一段字符串

这一小的操作中会出现两段字条串,一段类似这样的

1
2
3
4
5
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,1FBB7A12C5332861D52FEDFA2E3E7AE3

....

复制内容保存为 /etc/ssl/certs/xxxx.crt
一段类似这样的

1
2
3
-----BEGIN CERTIFICATE-----
MIIGdTCCBV2gAwIBAgIDYTrWMA0GCSqGSIc3FQEBBQUAMIGMMQswCQYDVQQGEwJJ
...

复制内容保存为 /etc/ssl/certs/xxxx.key

下面就是配置你的VPS上的NGINX服务器了。

vi /usr/local/nginx/conf/vhost/xxxx.conf

在Server里添加

1
2
3
4
5
6
7
8
listen 443 ssl spdy;
ssl on;
ssl_certificate /etc/ssl/certs/xxxx.crt;
ssl_certificate_key /etc/ssl/certs/xxxx.key;
ssl_session_timeout 10m;
ssl_protocols SSLv2 SSLv3 TLSv1;
ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
ssl_prefer_server_ciphers on;

如果你想让http跳转到https下,需要再加一段代码

1
2
3
if ($ssl_protocol = "") {
rewrite ^/(.*)$ https://www.domain.com/$1 permanent;
}

如果出现循环重定向,检查下你的网站根目录下,是否有.htaccess文件,因为我的服务器是lnmpa的,apache的重定向文件还是会起作用的,检查下有无重定向到http的,一般是301重定向需要修改下。

上面这些做完之后,还需要另外对firefox浏览器作一些配置更改
/etc/ssl/certs/xxxx.crt所在目录执行以下代码

1
2
wget http://cert.startssl.com/certs/sub.class1.server.ca.pem
cat ca.pem sub.class1.server.ca.pem >> xxxx.crt

就是向 xxx.crt里面追加一些内容,这样firefox就不会提示证书不安全了。

下就是重启你的nginx服务器,但这里会提示你需要输入Enter PEM pass phrase
总不能每次重启都要输入那个密码吧,这个可以跳过的,方法按照我之前的一篇文章操作

/313864/lnmp%E4%B8%8Bnginx%E9%85%8D%E7%BD%AEssl%E5%AE%89%E5%85%A8%E8%AF%81%E4%B9%A6%E9%81%BF%E5%85%8D%E5%90%AF%E5%8A%A8%E8%BE%93%E5%85%A5enter-pem-pass-phrase/

SPDY协议安装

你要先下载最新的 OpenSSL,比如 1.0.1e,这里是下载列表,红色标注的就是最新版了。因为前些时间的openssl漏洞,现在linode好像自动已经升级到最新版1.0.1e了。

但还是需要下载,解压

1
2
3
cd /tmp
wget http://www.openssl.org/source/openssl-1.0.1e.tar.gz
tar zxvpf openssl-1.0.1e.tar.gz

然后下载最新的Nginx

先用 /usr/local/nginx/sbin/nginx -V 这个是查看nginx安装了什么模块 安装的时候把这些都再加上

1
2
3
4
5
6
7
8
9
wget http://nginx.org/download/nginx-1.7.2.tar.gz
tar zxvf nginx-1.7.2.tar.gz
cd nginx-1.7.2
./configure --user=www --group=www --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module --with-http_gzip_static_module --with-ipv6 --with-pcre --with-http_sub_module --with-http_spdy_module --with-openssl=/tmp/openssl-1.0.1e
mv /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.old
cp objs/nginx /usr/local/nginx/sbin/nginx
/usr/local/nginx/sbin/nginx -t
make upgrade
/usr/local/nginx/sbin/nginx -v

上面需要注意的是./configure --with-http_ssl_module --with-http_spdy_module --with-openssl=/tmp/openssl-1.0.1e 这是最小安装方法,你需要根据自己的配置安装,上面是lnmpa下面的。

--with-openssl=/tmp/openssl-1.0.1e 路径就是刚下载的那个路径。

再配置完成后,执行 /etc/init.d/nginx reload/usr/local/nginx/sbin/nginx -s reload 重载 Nginx 配置文件即可正常访问了。

如果你不想使用 SPDY ,记得修改Server里的 listen 443 ssl spdy; 改为 listen 443 ssl;

如何查看有没有启用SPDY成功没

在Chrome浏览器里打开 chrome://net-internals/#spdy 便能查看目前使用SPDY的连接。

或者使用插件查看, https://chrome.google.com/webstore/detail/spdy-indicator/mpbpobfflnpcgagjijhmgnchggcjblin

补充:关于 “此网页包含的脚本来自于身份未经验证的源” 的提示信息

出现这个一般是因为在网页内容中加载了其它不带https的内容,比如加载了google font,

1
<link href='http://fonts.googleapis.com/css?family=Antic+Slab' rel='stylesheet' type='text/css'>

一般解决办法就是把资源下载到本地,然后使用相对路径,或者使用https的资源地址。
google 支持https连接,上面的情况你可以直接改为

1
<link href='https://fonts.googleapis.com/css?family=Antic+Slab' rel='stylesheet' type='text/css'>

从Startssl免费申请到ssh证书后,把自己的一个网站搭建成了https网站。但是由于生成私钥key文件时输入了密码,导致每次重启nginx时都提示Enter PEM pass phrase , 这样会导致自己VPS上的重启脚本无法自动工作,每次都要人工重启。

在网上搜索后找到了解决办法。

在key的目录执行:openssl rsa -in server.key -out server.key.unsecure 然后在配置文件里使用unsecure这个文件名就行了

修改后的nginx配置如下:

1
2
3
4
5
6
7
8
9
10
# 这里是SSL的相关配置
server {
listen 443;
server_name www.example.com; # 你自己的域名
root /home/wwwroot/www.example.com;
ssl on;
ssl_certificate /etc/ssl/certs/server.crt;
# 修改下面这一行指向我们生成的server.key.unsecure文件
ssl_certificate_key /etc/ssl/certs/server.key.unsecure;
}

然后使用/etc/init.d/nginx restart重启Nginx.不提示便表示成功了。

背景

目前互联网上充斥着大量的关于RESTful API(为方便,下文中“RESTful API ”简写为“API”)如何设计的文章,然而却没有一个”万能“的设计标准:如何鉴权?API 格式如何?你的API是否应该加入版本信息?当你开始写一个app的时候,特别是后端模型部分已经写完的时候,你不得不殚精竭虑的设计和实现自己app的public API部分。因为一旦发布,对外发布的API将会很难改变。

在给SupportedFu设计API的时候,我试图以实用的角度来解决上面提到的问题。我希望可以设计出容易使用,容易部署,并且足够灵活的API,本文因此而生。

API设计的基本要求

网上的很多关于API设计的观点都十分”学院派“,它们也许更有理论基础,但是有时却和现实世界脱轨(因此我是自由派)。所以我这篇文章的目标是从实践的角度出发,给出当前网络应用的API设计最佳实践(当然,是我认为的最佳了~),如果觉得不合适,我不会遵从标准。当然作为设计的基础,几个必须的原则还是要遵守的:

  1. 当标准合理的时候遵守标准。
  2. API应该对程序员友好,并且在浏览器地址栏容易输入。
  3. API应该简单,直观,容易使用的同时优雅。
  4. API应该具有足够的灵活性来支持上层ui。
  5. API设计权衡上述几个原则。

需要强调的是:API的就是程序员的UI,和其他UI一样,你必须仔细考虑它的用户体验!

使用RESTful URLs 和action.

虽然前面我说没有一个万能的API设计标准。但确实有一个被普遍承认和遵守:RESTfu设计原则。它被Roy Felding提出(在他的”基于网络的软件架构“论文中第五章)。而REST的核心原则是将你的API拆分为逻辑上的资源。这些资源通过http被操作(GET ,POST,PUT,DELETE)。

那么我应该如何拆分出这些资源呢?

显然从API用户的角度来看,”资源“应该是个名词。即使你的内部数据模型和资源已经有了很好的对应,API设计的时候你仍然不需要把它们一对一的都暴露出来。这里的关键是隐藏内部资源,暴露必需的外部资源。

在SupportFu里,资源是 ticket、user、group。

一旦定义好了要暴露的资源,你可以定义资源上允许的操作,以及这些操作和你的API的对应关系:

1
2
3
4
5
*   GET /tickets # 获取ticket列表
* GET /tickets/12 # 查看某个具体的ticket
* POST /tickets # 新建一个ticket
* PUT /tickets/12 # 更新ticket 12.
* DELETE /tickets/12 #删除ticekt 12

可以看出使用REST的好处在于可以充分利用http的强大实现对资源的CURD功能。而这里你只需要一个endpoint:/tickets,再没有其他什么命名规则和url规则了,cool!

这个endpoint的单数复数

一个可以遵从的规则是:虽然看起来使用复数来描述某一个资源实例看起来别扭,但是统一所有的endpoint,使用复数使得你的URL更加规整。这让API使用者更加容易理解,对开发者来说也更容易实现。

如何处理关联?关于如何处理资源之间的管理REST原则也有相关的描述:

1
2
3
4
5
6
*   GET /tickets/12/messages- Retrieves list of messages for ticket #12
* GET /tickets/12/messages/5- Retrieves message #5 for ticket #12
* POST /tickets/12/messages- Creates a new message in ticket #12
* PUT /tickets/12/messages/5- Updates message #5 for ticket #12
* PATCH /tickets/12/messages/5- Partially updates message #5 for ticket #12
* DELETE /tickets/12/messages/5- Deletes message #5 for ticket #12

其中,如果这种关联和资源独立,那么我们可以在资源的输出表示中保存相应资源的endpoint。然后API的使用者就可以通过点击链接找到相关的资源。如果关联和资源联系紧密。资源的输出表示就应该直接保存相应资源信息。(例如这里如果message资源是独立存在的,那么上面 GET /tickets/12/messages就会返回相应message的链接;相反的如果message不独立存在,他和ticket依附存在,则上面的API调用返回直接返回message信息)

不符合CURD的操作

对这个令人困惑的问题,下面是一些解决方法:

  1. 重构你的行为action。当你的行为不需要参数的时候,你可以把active对应到activated这个资源,(更新使用patch).
  2. 以子资源对待。例如:github上,对一个gists加星操作:PUT /gists/:id/star 并且取消星操作:DELETE /gists/:id/star.
  3. 有时候action实在没有难以和某个资源对应上例如search。那就这么办吧。我认为API的使用者对于/search这种url也不会有太大意见的(毕竟他很容易理解)。只要注意在文档中写清楚就可以了。

永远使用SSL

毫无例外,永远都要使用SSL。你的应用不知道要被谁,以及什么情况访问。有些是安全的,有些不是。使用SSL可以减少鉴权的成本:你只需要一个简单的令牌(token)就可以鉴权了,而不是每次让用户对每次请求签名。

值得注意的是:不要让非SSL的url访问重定向到SSL的url。

文档

文档和API本身一样重要。文档应该容易找到,并且公开(把它们藏到pdf里面或者存到需要登录的地方都不太好)。文档应该有展示请求和输出的例子:或者以点击链接的方式或者通过curl的方式(请见openstack的文档)。如果有更新(特别是公开的API),应该及时更新文档。文档中应该有关于何时弃用某个API的时间表以及详情。使用邮件列表或者博客记录是好方法。

版本化

在API上加入版本信息可以有效的防止用户访问已经更新了的API,同时也能让不同主要版本之间平稳过渡。关于是否将版本信息放入url还是放入请求头有过争论:API version should be included in the URL or in a header. 学术界说它应该放到header里面去,但是如果放到url里面我们就可以跨版本的访问资源了。。(参考openstack)。

strip使用的方法就很好:它的url里面有主版本信息,同时请求头俩面有子版本信息。这样在子版本变化过程中url的稳定的。变化有时是不可避免的,关键是如何管理变化。完整的文档和合理的时间表都会使得API使用者使用的更加轻松。

结果过滤,排序,搜索:

url最好越简短越好,和结果过滤,排序,搜索相关的功能都应该通过参数实现(并且也很容易实现)。

**过滤:**为所有提供过滤功能的接口提供统一的参数。例如:你想限制get /tickets 的返回结果:只返回那些open状态的ticket–get /tickektsstate=open这里的state就是过滤参数。

**排序:**和过滤一样,一个好的排序参数应该能够描述排序规则,而不业务相关。复杂的排序规则应该通过组合实现:

1
2
*   GET /ticketssort=-priority- Retrieves a list of tickets in descending order of priority
* GET /ticketssort=-priority,created_at- Retrieves a list of tickets in descending order of priority. Within a specific priority, older tickets are ordered first

这里第二条查询中,排序规则有多个rule以逗号间隔组合而成。

**搜索:**有些时候简单的排序是不够的。我们可以使用搜索技术(ElasticSearch和Lucene)来实现(依旧可以作为url的参数)。

1
*   GET /ticketsq=return&amp;state=open&amp;sort=-priority,created_at- Retrieve the highest priority open tickets mentioning the word ‘return

对于经常使用的搜索查询,我们可以为他们设立别名,这样会让API更加优雅。例如:

1
get /ticketsq=recently_closed -> get /tickets/recently_closed.

限制API返回值的域

有时候API使用者不需要所有的结果,在进行横向限制的时候(例如值返回API结果的前十项)还应该可以进行纵向限制。并且这个功能能有效的提高网络带宽使用率和速度。可以使用fields查询参数来限制返回的域例如:

1
GET /ticketsfields=id,subject,customer_name,updated_at&amp;state=open&amp;sort=-updated_at

更新和创建操作应该返回资源

PUT、POST、PATCH 操作在对资源进行操作的时候常常有一些副作用:例如created_at,updated_at 时间戳。为了防止用户多次的API调用(为了进行此次的更新操作),我们应该会返回更新的资源(updated representation.)例如:在POST操作以后,返回201 created 状态码,并且包含一个指向新资源的url作为返回头

是否需要 “HATEOAS”

网上关于是否允许用户创建新的url有很大的异议(注意不是创建资源产生的url)。为此REST制定了HATEOAS来描述了和endpoint进行交互的时候,行为应该在资源的metadata返回值里面进行定义。

(译注:作者这里认为HATEOAS还不算成熟,我也不怎么理解这段就算了,读者感兴趣可以自己去原文查看)

只提供json作为返回格式

现在开始比较一下XML和json了。XML即冗长,难以阅读,又不适合各种编程语言解析。当然XML有扩展性的优势,但是如果你只是将它来对内部资源串行化,那么他的扩展优势也发挥不出来。很多应用(youtube,twitter,box)都已经开始抛弃XML了,我也不想多费口舌。给了google上的趋势图吧:

当然如果的你使用用户里面企业用户居多,那么可能需要支持XML。如果是这样的话你还有另外一个问题:你的http请求中的media类型是应该和accept 头同步还是和url?为了方便(browser explorability),应该是在url中(用户只要自己拼url就好了)。如果这样的话最好的方法是使用.xml或者.json的后缀。

命名方式?

是蛇形命令(下划线和小写)还是驼峰命名?如果使用json那么最好的应该是遵守JAVASCRIPT的命名方法-也就是说骆驼命名法。如果你正在使用多种语言写一个库,那么最好按照那些语言所推荐的,java,c#使用骆驼,python,ruby使用snake。

个人意见:我总觉得蛇形命令更好使一些,当然这没有什么理论的依据。有人说蛇形命名读起来更快,能达到20%,也不知道真假http://ieeexplore.ieee.org/xpl/articleDetails.jsptp=&arnumber=5521745

默认使用pretty print格式,使用gzip

只是使用空格的返回结果从浏览器上看总是觉得很恶心(一大坨有没有?~)。当然你可以提供url上的参数来控制使用“pretty print”,但是默认开启这个选项还是更加友好。格外的传输上的损失不会太大。相反你如果忘了使用gzip那么传输效率将会大大减少,损失大大增加。想象一个用户正在debug那么默认的输出就是可读的-而不用将结果拷贝到其他什么软件中在格式化-是想起来就很爽的事,不是么?

下面是一个例子:

1
2
3
4
$ curl https://API.github.com/users/veesahni > with-whitespace.txt
$ ruby -r json -e 'puts JSON JSON.parse(STDIN.read)' < with-whitespace.txt > without-whitespace.txt
$ gzip -c with-whitespace.txt > with-whitespace.txt.gz
$ gzip -c without-whitespace.txt > without-whitespace.txt.gz

输出如下:

1
2
3
4
*   without-whitespace.txt- 1252 bytes
* with-whitespace.txt- 1369 bytes
* without-whitespace.txt.gz- 496 bytes
* with-whitespace.txt.gz- 509 bytes

在上面的例子中,多余的空格使得结果大小多出了8.5%(没有使用gzip),相反只多出了2.6%。据说:twitter使用gzip之后它的streaming API传输减少了80%(link:https://dev.twitter.com/blog/announcing-gzip-compression-streaming-APIs).

只在需要的时候使用“envelope”

很多API象下面这样返回结果:

1
2
3
4
5
6
{
"data" : {
"id" : 123,
"name" : "John"
}
}

理由很简单:这样做可以很容易扩展返回结果,你可以加入一些分页信息,一些数据的元信息等-这对于那些不容易访问到返回头的API使用者来说确实有用,但是随着“标准”的发展(cors和http://tools.ietf.org/html/rfc5988#page-6都开始被加入到标准中了),我个人推荐不要那么做。

何时使用envelope?

有两种情况是应该使用envelope的。如果API使用者确实无法访问返回头,或者API需要支持交叉域请求(通过jsonp)。

jsonp请求在请求的url中包含了一个callback函数参数。如果给出了这个参数,那么API应该返回200,并且把真正的状态码放到返回值里面(包装在信封里),例如:

1
2
3
4
5
6
7
callback_function({
status_code: 200,
next_page: "https://..",
response: {
... actual JSON response body ...
}
})

同样为了支持无法方法返回头的API使用者,可以允许envelope=true这样的参数。

在post,put,patch上使用json作为输入

如果你认同我上面说的,那么你应该决定使用json作为所有的API输出格式,那么我们接下来考虑考虑API的输入数据格式。

很多的API使用url编码格式:就像是url查询参数的格式一样:单纯的键值对。这种方法简单有效,但是也有自己的问题:它没有数据类型的概念。这使得程序不得不根据字符串解析出布尔和整数,而且还没有层次结构–虽然有一些关于层次结构信息的约定存在可是和本身就支持层次结构的json比较一下还是不很好用。

当然如果API本身就很简单,那么使用url格式的输入没什么问题。但对于复杂的API你应该使用json。或者干脆统一使用json。

注意使用json传输的时候,要求请求头里面加入:Content-Type:application/json.,否则抛出415异常(unsupported media type)。

分页

分页数据可以放到“信封”里面,但随着标准的改进,现在我推荐将分页信息放到link header里面:http://tools.ietf.org/html/rfc5988#page-6。

使用link header的API应该返回一系列组合好了的url而不是让用户自己再去拼。这点在基于游标的分页中尤为重要。例如下面,来自github的文档

1
2
Link: <https://api.github.com/user/repos?page=3&amp;per_page=100>; rel="next", 
<https://api.github.com/user/repos?page=50&amp;per_page=100>; rel="last"

自动加载相关的资源

很多时候,自动加载相关资源非常有用,可以很大的提高效率。但是这却和RESTful的原则相背。为了如此,我们可以在url中添加参数:embed(或者expend)。embed可以是一个逗号分隔的串,例如:

1
GET /ticket/12embed=customer.name,assigned_user

对应的API返回值如下:

1
2
3
4
5
6
7
8
9
10
11
12
{
"id" : 12,
"subject" : "I have a question!",
"summary" : "Hi, ....",
"customer" : {
"name" : "Bob"
},
assigned_user: {
"id" : 42,
"name" : "Jim",
}
}

值得提醒的是,这个功能有时候会很复杂,并且可能导致N+1 SELECT 问题

重写HTTP方法

有的客户端只能发出简单的GET 和POST请求。为了照顾他们,我们可以重写HTTP请求。这里没有什么标准,但是一个普遍的方式是接受X-HTTP-Method-Override请求头。

速度限制

为了避免请求泛滥,给API设置速度限制很重要。为此 RFC 6585 引入了HTTP状态码429(too many requests)。加入速度设置之后,应该提示用户,至于如何提示标准上没有说明,不过流行的方法是使用HTTP的返回头。

下面是几个必须的返回头(依照twitter的命名规则):

1
2
3
*   X-Rate-Limit-Limit :当前时间段允许的并发请求数
* X-Rate-Limit-Remaining:当前时间段保留的请求数。
* X-Rate-Limit-Reset:当前时间段剩余秒数

为什么使用当前时间段剩余秒数而不是时间戳?

时间戳保存的信息很多,但是也包含了很多不必要的信息,用户只需要知道还剩几秒就可以再发请求了这样也避免了clock skew问题

有些API使用UNIX格式时间戳,我建议不要那么干。为什么?HTTP 已经规定了使用 RFC 1123 时间格式

鉴权 Authentication

restful API是无状态的也就是说用户请求的鉴权和cookie以及session无关,每一次请求都应该包含鉴权证明。

通过使用ssl我们可以不用每次都提供用户名和密码:我们可以给用户返回一个随机产生的token。这样可以极大的方便使用浏览器访问API的用户。这种方法适用于用户可以首先通过一次用户名-密码的验证并得到token,并且可以拷贝返回的token到以后的请求中。如果不方便,可以使用OAuth 2来进行token的安全传输。

支持jsonp的API需要额外的鉴权方法,因为jsonp请求无法发送普通的credential。这种情况下可以在查询url中添加参数:access_token。注意使用url参数的问题是:目前大部分的网络服务器都会讲query参数保存到服务器日志中,这可能会成为大的安全风险。

注意上面说到的只是三种传输token的方法,实际传输的token可能是一样的。

缓存

HTTP提供了自带的缓存框架。你需要做的是在返回的时候加入一些返回头信息,在接受输入的时候加入输入验证。基本两种方法:

**ETag:**当生成请求的时候,在HTTP头里面加入ETag,其中包含请求的校验和和哈希值,这个值和在输入变化的时候也应该变化。如果输入的HTTP请求包含IF-NONE-MATCH头以及一个ETag值,那么API应该返回304 not modified状态码,而不是常规的输出结果。

**Last-Modified:**和etag一样,只是多了一个时间戳。返回头里的Last-Modified:包含了 RFC 1123 时间戳,它和IF-MODIFIED-SINCE一致。HTTP规范里面有三种date格式,服务器应该都能处理。

出错处理

就像html错误页面能够显示错误信息一样,API 也应该能返回可读的错误信息–它应该和一般的资源格式一致。API应该始终返回相应的状态码,以反映服务器或者请求的状态。API的错误码可以分为两部分,400系列和500系列,400系列表明客户端错误:如错误的请求格式等。500系列表示服务器错误。API应该至少将所有的400系列的错误以json形式返回。如果可能500系列的错误也应该如此。json格式的错误应该包含以下信息:一个有用的错误信息,一个唯一的错误码,以及任何可能的详细错误描述。如下:

1
2
3
4
5
{
"code" : 1234,
"message" : "Something bad happened :-(",
"description" : "More details about the error here"
}

对PUT,POST,PATCH的输入的校验也应该返回相应的错误信息,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
"code" : 1024,
"message" : "Validation Failed",
"errors" : [
{
"code" : 5432,
"field" : "first_name",
"message" : "First name cannot have fancy characters"
},
{
"code" : 5622,
"field" : "password",
"message" : "Password cannot be blank"
}
]
}

HTTP 状态码

1
2
3
4
5
6
7
8
9
10
11
12
200 ok  - 成功返回状态,对应,GET,PUT,PATCH,DELETE.
201 created - 成功创建。
304 not modified - HTTP缓存有效。
400 bad request - 请求格式错误。
401 unauthorized - 未授权。
403 forbidden - 鉴权成功,但是该用户没有权限。
404 not found - 请求的资源不存在
405 method not allowed - 该http方法不被允许。
410 gone - 这个url对应的资源现在不可用。
415 unsupported media type - 请求类型错误。
422 unprocessable entity - 校验错误时用。
429 too many request - 请求过多。

参考资料

原文链接:Vinay Sahni,编译:感谢@bruce-accumulate 的热心翻译

译文链接:http://blog.jobbole.com/41233/

Github Page绑定二级域名或者顶级域名,需要做两件事,一个是在github page下面创建 CNAME文件,一个就是设置你的DNS。

CNAME

创建一个CNAME文件,内容是你的域名,如:
domain.org
然后把此文件添加到Github仓库,上传到Github。Github服务器会设置domain.org为你的主域名,然后将www.domain.org和demo.github.com重定向到domain.org。

有一个在线的编辑器  http://prose.io/ 使用它可以在线修改你的github page,非常方便,适合不会使用命令的同学。

如果是想绑定二级域名,上面的设置还是不够的,比如你想把二级域名sub.domain.org 绑定到 demo.github.com ,你需要在CNAME文件里加上sub.demo.org

DNS

登陆你的域名管理界面。创建一条A记录,指向207.97.227.245这个IP地址。
sub.domain.org为博客域名,指向Github Page。
需要做的设置:

  • 创建CNAME文件,内容为sub.domain.org
  • 登陆域名管理,创建CNAME记录,sub -> demo.github.com

Github作免费空间有300M的空间限制 。

上周招聘了一个年轻人。面试的时候,很有热情,准备充分,对公司也做了研究,连对话提问,明显也是之前有所排练的,总而言之,看起来是一个做事很认真的小伙子。

他说:我觉得,这就是我想要的公司和文化,这就是我喜欢的工作!
这个小伙子戴着黑框眼镜,说这话的时候,一副理想主义者的激情神态。

坦白说,我被这种神态打动了。
我想,也许工作充满繁杂无聊,但只有这种激情,才能造就卓越。

后来我又看了一下作品,觉得底子不错。决定录用。
很快HR给他发了OFFER。第二周就来上班了。

几天后,他给主管发了一条短信,说自己不喜欢这个工作。发短信第二天,他就不来了。连离职手续都没办。

主管跟我说起时,我还很惊诧。“这不可能吧?”
我觉得这种轻率行为,完全不像是那个年轻人该有的。

我很想和他谈谈,给他发了条短信。没回复。我准备给他拨个电话,但转念一想,又觉得没这个必要。

就算打通电话了,我想跟他谈什么呢?

劝他继续来公司?——不,我不会再要他了。这样的年轻人,我也不敢要。
跟他谈什么是“责任”?——都是成年人,也挺没意思。
谈“喜欢”和“工作”的关系?——我不是稻盛和夫,我说不出“与其找喜欢的工作,不如喜欢上手头的工作”这种话。

想来想去,我想给他讲讲我自己的故事。

我想说说,7年前的自己。

那时我大学还没毕业,在一家影视广告公司做脚本文案。写脚本很辛苦,影视广告也并不有趣。跟我之前的想象完全不同。

恰好异地恋的女友来找我。有一天,我跟老板连招呼都没打,跟行政说了一声我不干了,收拾东西就走了。

手机关机,跟女友过了几天与世隔绝、幸福快乐、没心没肺的日子,我突然觉得该给公司一个交代,于是硬着头皮去公司,找老板谈谈。

恰巧,在公司电梯口见到老板,带着一群人,扛着大小设备,急匆匆出去外拍。老板见到我,愣了一下,指着我说:等我,回来再跟你说。

我吓坏了。这个老板平时脾气就大,这下还不得把我训死?

我在公司提心吊胆等了一个小时。我看着公司其他人忙碌喧哗,根本顾不上理我。难堪之极。

我找了张纸,写了一封长信,放在前台。算是交代了一下。

总之,我是落荒而逃。

这就是我职业生涯的开始。一个不光彩的、污点般的开始。

我想找那个年轻人,聊聊这件事。

我想告诉他,这件事成为我后来久久无法磨去的尴尬,心灵上的痒痕。

在那之后,我经常在洗澡的时候会突然想起自己落荒而逃的身影,内心奇痒无比,忍不住要狂嚎两嗓子才能疏解。

后来,我正式进入广告传播行业,在一家本土创意公司做了3年,后跟总监出来创业,到今年是第4年。

2012年的时候,机缘巧合,我又见到了当初那家影视公司的老板。

毕竟事过多年,我已经有了一颗平常心,能够跟人家主动打招呼了。他还记得我,很热情的跟我握手,问我近况,称赞我“有才华”,看上去一点也记不起来当初在电梯口的尴尬相遇。

我们一起吃了个饭,相约以后有机会合作。

此后,我们再也没有见过。

那次见面之后,我彻底原谅了自己。我也明白了一件事——几乎所有你认为尴尬的事,都只有你自己记得。别人早已忘却或不放在心上,只有你自己,当成久久无法消逝的“心头之痒”。

回望过去,我那个时候,很喜欢王小波。王小波有一篇文章,叫《工作与人生》。我当时读了没什么大的感受,比不上读《一只特立独行的猪》这么过瘾。
但现在回过头再看,这篇文章简直每一个字都写进了我的心里。

其中有三句,犹得我心:

**第一句是:“人从工作中可以得到乐趣,这是一种巨大的好处。”

第二句是:“总而言之,干什么都是好的;但要干出个样子来,这才是人的价值和尊严所在。”

第三句是:“人在工作时,不单要用到手、腿和腰,还要用脑子和自己的心胸。”**

不知不觉,我发现自己在面对工作时,态度与自己的人生偶像完全一致了。这让我感到振奋。
仿佛我经历了一次连自己都未察觉的修炼。如今已经印证,修为在身,境界如常。

而这种面对工作的态度和认知,是从什么时候开始的呢?就是从那段难堪的起点开始的,从那久久无法消散的心头之痒开始的。
那段难堪的经历,以及后来不断的自我反省,以及多年来全心投入工作的历练,使我重新认识了“工作”这件事。以及我应该如何对待“工作”。

是的。假如我有机会再见到那个年轻人,我会跟他谈谈以上这些。

原文: http://jianshu.io/p/6ff3d4113be6

引言

写程序的时候经常要处理命令行参数,本文描述在Bash下的命令行处理方式。

选项与参数:

如下一个命令行:

1
./test.sh -f config.conf -v --prefix=/home

我们称-f为选项,它需要一个参数,即config.conf, -v 也是一个选项,但它不需要参数。

–prefix我们称之为一个长选项,即选项本身多于一个字符,它也需要一个参数,用等号连接,当然等号不是必须的,/home可以直接写在–prefix后面,即–prefix/home,更多的限制后面具体会讲到。
在bash中,可以用以下三种方式来处理命令行参数,每种方式都有自己的应用场景。

  • 手工处理方式
  • getopts
  • getopt

下面我们依次讨论这三种处理方式。

手工处理方式

在手工处理方式中,首先要知道几个变量,还是以上面的命令行为例:

  • $0 : ./test.sh,即命令本身,相当于C/C++中的argv[0]
  • $1 : -f,第一个参数.
  • $2 : config.conf
  • $3, $4 … :类推。
  • $# 参数的个数,不包括命令本身,上例中$#为4.
  • $@ :参数本身的列表,也不包括命令本身,如上例为 -f config.conf -v –prefix=/home
  • $* :和$@相同,但”$“ 和 “$@”(加引号)并不同,”$“将所有的参数解释成一个字符串,而”$@”是一个参数数组。如下例所示:
1
2
3
4
5
6
7
8
9
10
11
#!/bin/bash

for arg in "$*"
do
echo $arg
done

for arg in "$@"
do
echo $arg
done

执行./test.sh -f config.conf -n 10 会打印:

1
2
3
4
5
6
7
8
9
-f config.conf -n 10 #这是"$*"的输出

-f #以下为$@的输出

config.conf

-n

10

所以,手工处理的方式即对这些变量的处理。因为手工处理高度依赖于你在命令行上所传参数的位置,所以一般都只用来处理较简单的参数。如

./test.sh 10

而很少使用./test -n 10这种带选项的方式。 典型用法为:

1
2
3
4
5
6
7
8
9
#!/bin/bash

if [ x$1 != x ]
then
#...有参数
else
then
#...没有参数
fi

为什么要使用 x$1 != x 这种方式来比较呢?想像一下这种方式比较:

if [ -n $1 ] #$1 不为空

但如果用户不传参数的时候,$1为空,这时 就会变成 [ -n ] ,所以需要加一个辅助字符串来进行比较。

手工处理方式能满足大多数的简单需求,配合shift使用也能构造出强大的功能,但在要处理复杂选项的时候建议用下面的两种方法。

getopts/getopt

处理命令行参数是一个相似而又复杂的事情,为此,C提供了getopt/getopt_long等函数,
C++的boost提供了Options库,在shell中,处理此事的是getopts和getopt.

getopts和getopt功能相似但又不完全相同,其中getopt是独立的可执行文件,而getopts是由Bash内置的。

先来看看参数传递的典型用法:

  • ./test.sh -a -b -c : 短选项,各选项不需参数
  • ./test.sh -abc : 短选项,和上一种方法的效果一样,只是将所有的选项写在一起。
  • ./test.sh -a args -b -c :短选项,其中-a需要参数,而-b -c不需参数。
  • ./test.sh –a-long=args –b-long :长选项

我们先来看getopts,它不支持长选项。

使用getopts非常简单:
代码

#test.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/bin/bash

while getopts "a:bc" arg #选项后面的冒号表示该选项需要参数
do
case $arg in
a)
echo "a's arg:$OPTARG" #参数存在$OPTARG中
;;
b)
echo "b"
;;
c)
echo "c"
;;
?) #当有不认识的选项的时候arg为?
echo "unkonw argument"
exit 1
;;
esac
done

现在就可以使用:
./test.sh -a arg -b -c

./test.sh -a arg -bc
来加载了。

应该说绝大多数脚本使用该函数就可以了,如果需要支持长选项以及可选参数,那么就需要使用getopt.
下面是getopt自带的一个例子:

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
#!/bin/bash

# A small example program for using the new getopt(1) program.
# This program will only work with bash(1)
# An similar program using the tcsh(1) script language can be found
# as parse.tcsh

# Example input and output (from the bash prompt):
# ./parse.bash -a par1 'another arg' --c-long 'wow!*\?' -cmore -b " very long "
# Option a
# Option c, no argument
# Option c, argument `more'
# Option b, argument ` very long '
# Remaining arguments:
# --&gt; `par1'
# --&gt; `another arg'
# --&gt; `wow!*\?'

# Note that we use `"$@"' to let each command-line parameter expand to a
# separate word. The quotes around `$@' are essential!
# We need TEMP as the `eval set --' would nuke the return value of getopt.

#-o表示短选项,两个冒号表示该选项有一个可选参数,可选参数必须紧贴选项
#如-carg 而不能是-c arg
#--long表示长选项
#"$@"在上面解释过
# -n:出错时的信息
# -- :举一个例子比较好理解:
#我们要创建一个名字为 "-f"的目录你会怎么办?
# mkdir -f #不成功,因为-f会被mkdir当作选项来解析,这时就可以使用
# mkdir -- -f 这样-f就不会被作为选项。

TEMP=`getopt -o ab:c:: --long a-long,b-long:,c-long:: \
-n 'example.bash' -- "$@"`

if [ $? != 0 ] ; then echo "Terminating..." &gt;&amp;2 ; exit 1 ; fi

# Note the quotes around `$TEMP': they are essential!
#set 会重新排列参数的顺序,也就是改变$1,$2...$n的值,这些值在getopt中重新排列过了
eval set -- "$TEMP"

#经过getopt的处理,下面处理具体选项。

while true ; do
case "$1" in
-a|--a-long) echo "Option a" ; shift ;;
-b|--b-long) echo "Option b, argument \`$2'" ; shift 2 ;;
-c|--c-long)
# c has an optional argument. As we are in quoted mode,
# an empty parameter will be generated if its optional
# argument is not found.
case "$2" in
"") echo "Option c, no argument"; shift 2 ;;
*) echo "Option c, argument \`$2'" ; shift 2 ;;
esac ;;
--) shift ; break ;;
*) echo "Internal error!" ; exit 1 ;;
esac
done
echo "Remaining arguments:"
for arg do
echo '--&gt; '"\`$arg'" ;
done

比如我们使用

./test -a -b arg arg1 -c

你可以看到,命令行中多了个arg1参数,在经过getopt和set之后,命令行会变为:
-a -b arg -c -- arg1
$1指向-a,$2指向-b,$3指向arg,$4指向-c,$5指向–,而多出的arg1则被放到了最后。

总结

一般小脚本手工处理也许就够了,getopts能处理绝大多数的情况,getopt较复杂,功能也更强大。
有问题请指出,不胜感激。

原文:http://www.cnblogs.com/FrankTan/archive/2010/03/01/1634516.html
参考资料:http://su1216.iteye.com/blog/1926382

结合静态站点托管服务Github Pages与博客生成工具Jekyll,搭建博客站点,有着部署成本低、易于维护的特点。诚然,Jekyll可以与Github Pages无缝集成,专业人士通过pull request就可以发布内容,但不易用是其最大的问题。Prose是一个基于Github PagesJekyll内容编辑器,它的出现使得内容编辑更快、更方便。

开通Github Pages服务

Github项目首页,点击进入后台管理页面

图1:Github项目管理后台入口[1]

点击”Automatic Page Generator”按钮生成站点服务

图2:Github项目页面生成器[1]

使用Markdown标记语言编辑站点内容,点击”Continue To Layouts”按钮

图3:Github项目页面预览[1]

预览并发布

图4:Github项目页面发布[1]

到这里,一个Github站点就生成了:http://{accountName}.github.com/{projectName}

使用Prose所见即所得的编辑特性

尝试Prose非常简单,首先通过Github账户身份验证,便可以导航到相应的站点

图5:Prose验证页面[2]

着陆页会依次列举个人代码库(Repository)

图6:Prose代码库列表[2]

选中之前开通Github Pages服务的代码库,可以浏览相应的文件以及创建新的文本文件

图7:Prose代码库内容列表[2]

编辑内容的时候,Prose支持Markdown标签的高亮显示

图8:Prose编辑器高亮特性[2]

任意时刻,都可以点击”Preview”按钮预览当前编辑的内容

图9:Prose编辑器预览特性[2]

Prose附加特性

在菜单工具条点击”M”按钮,可以获取Markdown标签参考语法列表

图10:Prose编辑器Markdown语法参考[2]

在菜单沟工具条点击”Metadata”按钮,可以看到文档的元数据以YAML的格式展现

图11:Prose编辑器元数据特性[2]

Prose项目的架构特点与展望

Prose的架构实现是以BackboneJekyll为基础,应用托管在Github上,浏览器端直接与GitHub API交互。鉴于浏览器端无法直接与Github通过OAuth交互,服务器后端处理用户身份的验证,具体的实现可参照Gatekeeper

感兴趣的读者朋友既可以选择Prose作为Github项目博客的内容编辑器,又可以参与Prose**项目的建设(Prose**完全基于BSD开源协议),搭建本地开发环境请参照http://prose.io/help/internals.html

引用

[1] https://help.github.com/articles/creating-pages-with-the-automatic-generator

[2] http://developmentseed.org/blog/2012/june/25/prose-a-content-editor-for-github/

原文: http://www.infoq.com/cn/news/2012/07/prose-github-content-editor

0%