multipartform-data

Part multipart/form-data 由许多块part组成,每一块之间由boundary分隔开 每一块都有自己的header Content-Disposition: form-data; name="user" //or Content-Disposition: form-data; name="user"; filenmae="image.png" 每一块都可以有一个可选的Content-Type字段,默认为text/plain,如果是文件类型,而且不知道其MIME,那么应该设置为application/octet-stream Content-Type: image/png 每一块的header和body之间都会有一个空行 每一行的结尾都应该用CRLF(\r\n) Tips 前端发来的filename不应该信任 name应该独一无二 name和filename都需要Percent-Encoding,应该避免Non-ASCII boundary boundary 应该放在Content-Type 中 Content-Type: multipart/form-data; boundary=abcedfghijk 每个part之间的分隔线由--,boundary,CRLF组成,每个part之前都需要放置一个。最后一个分割线需要加上--后缀。比如 --abced Content-Disposition: form-data; name="user" uservalue --abced Content-Disposition: form-data; name="file"; filenmae="image.png" Content-Type: image/png �PNG ffffff --abced-- 背景知识 Percent-Encoding,也叫做URL Encoding。https://en.wikipedia.org/wiki/Percent-encoding

September 15, 2019

ThoughtWorks 1

我是2018年年底加入ThoughtWorks,招聘的原因在事后看来也很有意思,某大公司的某部门年底预算用不完,需要找点事做,所以就起了一个项目,TW就为这个项目招了一批人。 这个项目是一个大杂烩项目,把所有能揉在一起的应用都揉在一起。第一次去客户现场是和另一个后端同事,当时是去商量两个模块,A和B,出发之前商量是两个人一起做两个模块。去了之后,就是和第三方的vendor讨论接口,实际上就是甩活,看你如何把一些脏活累活扔给对方,这点恰恰是我的强项,但是我是个新人,所以第一轮商讨的时候,主力是另外一位同事,一轮谈下来,我就和同事商量:“要不这个B你做吧,我做A就好了……”,不得不说,和第三方打交道不强硬就等于吃亏。 于是我就开始了A开发,我在SMZDM没有参与业务开发长达两年,在TW的第一个项目,依然是没有开发任务,天天嘴炮,说服前端接受API,说服上游vendor修改接口。在这个过程中,被灌输了BFF和Contract Testing这两个概念。 契约测试,这个是一个美好的理念,蹩脚的实现,残酷的现实。 BFF,一次性代码,帮前端包鸡包眼的代名词。 到了项目后期,IM的同事下项目,我接手,和第三方对接,这个时候,历练和成长才由此开始。 与第三方无止境的扯皮。 讨论的时候:这个接口调一下就行了! 第二天实施:你们先调用A,再调用B,然后把xxx弄一下,不就行了吗? 讨论的时候:好的,没问题,那我们就这么改。 第二天实施:我们没答应,我的原意是回去研究下,我们研究结果是不可行…… 与此我也总结出了许多“经验”: 不在客户面前说没把握的事 只说事情的表现,不帮第三方去猜原因 保留证据,并引导第三方犯上面的错 不要一次性要求第三方解决N个问题,选择一个,咬住不松口 多发问,少解释。除非是客户问你bug的原因,你能甩给第三方,但也要注意前面说的,不要去猜测第三方的原因。 项目后期就非常无趣了,没写代码没实际产出物被diss,小组效率被质疑,BA夹在小组和PM之间为难…… 2019年5月,我下了这个项目。 小插曲 在on beach了一个多月之后,某天被RM拉过去“北京的TP点名要你上O项目,和他一起balabala”,同时也从Buddy口中听到了类似的声音。当时的我受宠若惊,TP,什么概念。上了O项目,才发现,原来不是这样,O项目想上契约测试,TP便问了之前项目的一个TL,得知我做过契约测试,并且处于on beach状态,就让我过去了。这个事情不知道怎么就变成TP点名要我了。扯淡的很。 反正上了O项目一周,我就主动要求下项目了,原因很简单 不喜欢写测试 尤其不喜欢契约测试 更加不喜欢帮别人写测试 更加更加不喜欢帮别人写契约测试 和PM说了之后,最开始是想在该Account下其他项目做,但是应该是我这种“刺头”没人愿意要,我便再次回到了on beach的状态。

May 1, 2019

我的这两年

今天是2018.10.22,可能是我在上海生活的最后一天,2016.02.16,我来到上海,那时的我还没有毕业,至于为什么来上海实习,其实没有为什么,就是觉得“年轻人应该出去走走”,至于为什么是上海而不是北京,广州……可能是上海,“魔都”这个称号真的是充满魔力。 找工作 来之前就沟通了三家还是四家面试,当时的我稚嫩的很,基础没有,经验没有,最擅长的就是面向Google编程,各种解决办法囫囵凑一块,总能解决问题,水平最差,热情最高。 第一家公司是闯奇,一家做积分墙业务的小公司,技术面试内容不大记得了,我只记得当时XYK给我很自豪的分享他对于redis ZSET的使用,以及原来用webmagic,后面又为啥弃用…… 当天上午面试,中午我就拖着箱子进公司了,成了CQASO项目组的第二名成员。 第二天就迎来了第三名成员,也是一名实习生(CYT)。 这说对我来说是最好的开头了。 开始工作 热情高涨的投入工作,XYK对我也是非常信任,经常夸我,让我觉得有点难堪(我这么弱……)。当然,这也鼓励着我往着好的方向发展。 几乎是一天发布N次,一周几个版本,更迭速度是我这几年来见过最快的,当时没多想,现在觉得CYT真奇才,前端真的牛的一逼,后端那样更迭,也能跟上。 技术上也是各种更新换代,开始抛弃祖传的xml配置,开始使用SpringBoot,开始使用MongoDB,集群,开始越来越多的使用lambda表达式(最开始XYK大规模使用的时候,我还觉得影响了代码可读性,后面,嗯,真香。),自学Kotlin,开始不囿于“怎么样才能搞定”,追求“为啥这样能搞定”。 抛开技术,产品也是全程参与,不得不说这个时期的小团队战斗力真的惊人,我也体验了一把”人人都是产品经理“。可以说CQASO,我也是有自己的感情在里面的,但是囿于当时我们的技术水平,我们只能在采集,整理,展示方面做到了自认非常不错的水平,最重要的数据背后的规律,我们确实没有什么好的办法,即便当时跟风上了Hadoop那一套,找了一些算法,效果也是不尽如人意。 厌倦 经过了7-8个月的开发,我们与竞品之间已经没有什么差距了,除了稳定性,不过事后复盘,稳定性的问题确实很大,很多用户都是经历了几次bug就跑掉了。老板开始对项目失去了信心,这个项目成了一个面子工程,用来彰显公司是一家高科技公司。开始了洗脑,早报那一套,我可能深受阶级斗争思想的荼毒,非常非常厌恶这一套,团队内部也开始有了抱怨,不得不说,抱怨是会传染的,特别是这种关系很融洽的小团队,到了17年2月,终于,团队散伙了。 再次找工作 这个时候的我,比较无知,但是想得很多,我开始向往大公司,觉得小公司随时有产品崩掉之后整各种幺蛾子的风险。一周投了好几十家,拉钩各种不匹配(觉得可能大部分是自动拒的,我没差到连面试都进不了),面试了两三家公司,收到offer的就只有什么值得买,当时看来,真的是梦想中的公司。 我是SMZDM老用户,特别喜欢这家公司 面试官问的问题都是我喜欢的问题(怎么解决一个问题,而不是哪个参数怎么配置 不再参与CRUD,而是参与集团内部基础设施和架构的研发 简直不要太美好,这次工资被压的比较低,个人感觉应该是比市场价少了20%,不管,开心就好。 纠结 进了SMZDM,才发现不是我想象中的那样 面试的leader马上要离职 300多人的技术规模,只有10来个是Java 整体技术水平怎么说呢,说出来就得罪人的水平 这就导致了内部基础设施和架构都搞不起来。(难度非常高,我做不到 还有一个小小的点是,我和面试我的leader都是非常强势且固执的人,当然我很尊重他(哈哈,Respect),但是两个人合作确实会有一些不愉快。 这导致了我进公司当天回家就写了一封邮件表示不合适 混乱 就这样开始了混的一年多,基本上做的东西都是,emm,怎么说呢,都是我不会跟人主动说的东西…… 技术变化可以说,基本没有,但是终于,被逼着开始看源码了,因为有些问题你压根搜不到任何解决方案,说的就是某些国内大厂的开源产品,管生不管养,文档全靠微信群,QQ群口口相传。 中间也间歇性踌躇满志,想离职,换个公司好好做点东西,但还是被持续性混吃等死给打败了。 //2018年12月17日晚上8点09分继续,毕竟我是一个很拖拉的人 等到离职才发现,我在SMZDM只做了这么一点东西,半成品(其实就是垃圾)CI,支付SDK(其实我觉得还行,但是还有改善的余地),配置中心(凑合能用,但是不算优秀),改了一下CAS,改了一下ES的Netty模块,对CAT有点头痛医头,脚痛医脚的修改。一年半(2017.03-2018.08)就只做了这么一点。实在是对不起公司。 在这里需要特别感谢我的领导LC,给与了我非常多的不应该的宽容。我感觉I don’t deserve it。 结束 2018年是我的本命年,可以说整一年都不太顺,年初出去玩,脚扭了。休息了整个3月,然后七月份,我爷爷重病去世,这是我第一次体会到,亲人离我而去,至今我还经常梦到我爷爷。这也让我意识到,过去的就已经过去了。等我再次回到上海,我已经不想继续上班了。其实现在回想,真的就是不想上班,所谓的一大堆理由,就是不想上班,我提出了离职,LC还是同意了我的离职,我何德何能,能让别人这样对待?7月底,我办完了离职流程,我突然就想回到武汉了。是的,突然就想回武汉了,所谓的理由都是假的,就是脑中冒出这么一个想法,然后践行了而已。 再次感谢我的领导,LC。以及我的各位SMZDM的同事,给与我的各种不应该的宽容。 回武汉 7月底离职,整个8月都在玩游戏。9月份投了小米云服务,没有做任何准备,电话面试的时候凭感觉侃侃而谈,然后挂掉了,很合理,我毫无怨言。 然后就放弃了整个9月,又开始了混吃等死的生活,BTW,合金装备5真的是一个非常非常棒的游戏。十月份,我再次开始了投简历,小米的IoT服务将我捞了起来,我又投了金山,海康,ThoughtWorks,还有两个不知名公司,金山面试我就知道自己挂了,海康面试非常简单,不知名公司中一个我觉得非常有把握,另外一个我压根瞧不上。IoT再次面试我觉得表现不错,TW的面试我也觉得还行。后来没想到两家小公司我都挂了(其中一家表现的对我非常认可),海康给的是童工合同,TW压价也厉害(多次打电话问最低多少完全不能接受)。 这里可以谈下小米IoT被挂掉的最后一次面试(第4次)。To be honest,让人非常不爽,问我overloads和override的区别,各种鸡毛蒜皮的问题。这里还是要说,WCNM,这种JB问题真的有意思嘛? 回到武汉 最后我来到了TW,一个外包公司,我在V2EX看到过几次TW的招聘帖,不管TW这边怎么吹,在我心中TW都是一家外包公司,但是我没得选了。 外包公司是原罪,但是To be honest,很多公司连外包公司都不如。 女朋友领导得知我去了TW,第一反应是"养老公司"。 不管怎么样,我进了这么一家养老公司。 我在来TW之前看了一些TW的差评。 会吹牛逼吗?会的话可以去TW,想学吹牛逼吗?想的话可以去TW。 可以说,这句非常贴切。 生活还得继续 入职TW也有一个多月了,当我一件一件的拆到女朋友从上海发来的包裹的时候,我开始意识到,我这辈子可能就和上海说再见了,我可能就在武汉买房,上班,结婚,生孩子,直到一生结束。 后记 我总是能开一个好头,然后后续乱七八糟…… 其实写了这么乱七八糟的一些,我也不知道我写了什么。 但是感谢XYK,CYT给我的鼓励和激励。...

October 22, 2018

23树实现

这几天在看HashMap中的红黑树,发现较为复杂,就从2-3树开始完整实现了一遍。 为啥会有2-3树 最合理的情况下,是有一棵满二叉树。但是构造一棵满二叉树并不容易。看一下二叉树的一般生长过程 二叉树在生长过程中,无法保持总是满的(我给你两个数,你给我弄个满二叉树 生长一般是自顶向下的,左右子树的树高容易不一致(极端情况下,退化成链表 如果第2步,不急着分清父子,第3步才来生成一棵2-Tree的话,就能得到一棵满树。 同样的推广到4,5步,再重新变形一下 emmm,这好像不是一棵满树啊。因为依旧是向下生长,并没有改变其左右不均匀的问题。那我们试着往上试试。 看起来除了A有两个爸爸,其他好像没啥问题啊。依然满足节点左侧所有点小于节点,右侧所有点大于节点。稍微变形一下 一棵满的3-Tree闪亮登场。 生成2-3树 插入 对于2-3树的每个叶子节点来说,只有两种情况 空2-Tree变成空3-Tree 空3-Tree变成满2-Tree 升级 当叶子节点由空3-Tree变为满2-Tree的时候,我们选择往上生长,这个过程就叫它升级好了。也只有两种情况 满2-Tree的子结点由空3-Tree变成满2-Tree,整个满2-Tree变成满3-Tree 满3-Tree的子结点由空3-Tree变成满2-Tree,整个满3-Tree变成满4-Tree,再分解成满两棵满2-Tree,树高+1 伪代码实现 首先定义树 class Tree { var p: Tree? = null //父亲 var v: LinkedList<Int> = LinkedList() //结点值 var c: LinkedList<Tree> = LinkedList() //子结点 val type get() = "${v.size}-${c.size}" //根据值的数量和子结点数量确定树的类型 } 然后就是插入代码 fun insert(tree: Tree) { when (tree.type) { "1-0" -> {//添加一个单点 when (this....

September 30, 2018

Windows下Terminal解决方案

不得不说Windows的Terminal实在是太不友好了。 CMD,没啥好说的,要死的玩意儿。 PowerShell,知乎上吹的比较厉害,但是另起一套,和*nix上完全不一样,学习成本不划算,何况我并不是一个专业用户。 WSL,知乎吹的更厉害了,用这玩意儿,各个开发的SDK得准备两套,简直神经病。而且,一个实现不完整的Linux == 不能用的Linux。 ...

September 15, 2018

Esxi 安装 Openwrt

新建虚拟机,添加一块小硬盘,4G足矣,再添加一个光驱,加载一个Linux ISO(只是需要一个Shell命令 启动虚拟机,选择从光盘启动。 ...

September 15, 2018

堆排序

堆排序 将数组看成一个二叉堆,大致就是这样的 父节点要大于子节点 简单一点,遍历整个树,每个节点都和父节点比较,如果大于父节点,则交换位置 tailrec fun casWithFather(array: IntArray, index: Int) { if (index == 0) { //第一个节点 do nothing } else { //和父节点比,如果大于父节点,递归和父节点比。 val parent = (index + 1) / 2 - 1 if (array[parent] < array[index]) { array.swap(index, parent) casWithFather(array, parent) } } } 最大堆排序 经过上一步的处理,这个堆已经满足了父节点大于子节点,为一个最大堆。 如何来利用最大堆排序呢,我们取出最大的父节点,然后再生成最大堆。 取出最大父节点 与最尾端节点交换位置 对新的堆排序(排除掉取出放在尾端的节点) tailrec fun casWithChild(array: IntArray, farther: Int, end: Int) { val lc = farther * 2 + 1 //左节点 val rc = farther * 2 + 2 //右节点 if (lc >= end) {//到达了需要排序"堆"的终点 return } val better = if (rc >= end || array[lc] > array[rc]) { lc } else { rc } if (array[farther] < array[better]) { array....

August 20, 2018

希尔排序

希尔排序 希尔排序是基于插入排序的一个演进 插入排序很大一部分开销在于插入这个操作上,后面所有的数据都需要移动。 分割 我们先按N为步进来分割数组,如下为N=4 1 5 9 …… 2 6 10 …… 3 7 11 …… 4 8 12 …… 对每个子数组进行排序 合并 实际上就是不分割数组,进行插入排序。 优点 分割之后,每个数组较小,能减少移动次数。 合并时,整个数组都是部分有序的,也能减少移动次数。

August 20, 2018

归并排序

简单版本 两个已经排序好的数组, 1,3,5,7,8,9...... 2,4,5,7,10...... 显而易见,用两个指针m、n,分别指向两个数组的开头 比较m、n大小 小的指针所在点放入新数组,并将该指针向后移动一位 重复比较,移动 最后有一个指针到了尽头,将另外的指针剩余部分放入新数组尾部 这样就完成了排序。 有序?不存在的 如果只有一个数组,而且是无序的,想要使用归并排序,怎么办? 按长度分成2个数组,是有序的话,就归并 不是有序的,分成4个数组,是有序的话,就归并 还不是有序的,一直分成有序的为止,此时每个数组长度为1 然后归并 代码 static void sort(int[] array) { for (int i = 1; i < array.length / 2; i *= 2) { int step = i * 2; for (int j = 0; j + step <= array.length; j += step) { merge(array, j, i, i); } final int left = array.length % (i * 2); if (left > 0) { merge(array, array....

August 20, 2018

QNAP TS-453Bmini 体验

很早之前就有弄一台服务器或者NAS放家里的想法, 从树莓派,工控板,Gen8,到ITX小板,几乎各种方案都在我脑海中过了一遍。 最近京东618将至,又开始看起各种PC配置和NAS,虽然我很清楚没啥卵用,但是后面想到,干脆当作给自己买一个玩具好了。 ...

June 13, 2018