序言
经常有产品新人问我技术问题。像是前后端的区别?数据库是怎么样的?如何和研发沟通?
回答的多了,就想系统化的回答,写一本书,让技术变得通俗易懂、有趣。
6年间,从技术小白=>工程师=>后台、数据产品经理,2000多个日夜,为代码、需求绞尽脑汁、也在创业路上走过,百感交集。
本书以小说故事的形式、场景化讲解技术,让枯燥的技术变得有趣。
感谢一些帮助我的小伙伴,谢谢。另提下里面的人物用的是脸萌设计的,侵删(设计师正在设计人物)
封面
故事背景
故事也很简单,两条主线,李大仁来深圳的创业故事,表妹小奈和小明的爱情故事。
小明和小奈恋爱,程序员和产品经理的爱情故事
大仁用户量破亿,一番挫折后破土而出,创业进入新阶段,拿到了B轮融资
人物关系
课程目录
总共有13章,50多小篇。
1、李大仁来深创业-互联网介绍
离开广州
“故事的小黄花 从出生那年就飘着 童年的荡秋千 随记忆一直......“。
李大仁听着歌,望着广州,这座生活了快10年的城市。脑中闪过了大学生活、同事、前女友,百感交集。但是为了最初的梦想,来到深圳创业。
来深创业
“各位乘客你好,列车已到站“。
终于迈出了这一步,深圳或许是创业氛围最好的地方了。
小奈:喂,表哥你在哪?
大仁:我在深圳北站。
刚到深圳,大仁决定投靠表妹那边,表妹家里在南山,离投资人提供的孵化器也很近。
大仁目前暂时住在表妹这边。小奈今年刚毕业,在一家大公司里当产品助理,非技术专业、初入职场的她遇到了挺多阻碍。
2018年,大仁今年也30岁了。
小奈:表哥,你女朋友呢?
大仁:分了,她不同意我来深圳这边创业。
落脚
小奈:表哥,你睡这间房吧。
大仁:好的。
互联网
疲累了一天,躺在床上,大仁陷入了沉思...
互联网,是网络与网络之间所串连成的全球网络,这里的网络可以理解成一个或多个电脑,这些网络以一组标准的网络TCP/IP协议族相连,互联网在信息层面把世界变成地球村。
互联网互通是全球性的,是属于全人类的。互联网低成本的、高效信息交流深受大家欢迎。它是是平等的,开放的信息高速公路,是人类发展进程的一个里程碑。
中国电商发展史
下图以中国互联网、电商发展史为例子。
三巨头BAT,崛起的TMD
中国互联网发展了20年,百度(B)阿里(A)腾讯(T)成为中国最大的三家互联网公司,形成了三组鼎力的格局,三家公司有各自的体系和地位,百度的搜索、阿里的电商、腾讯的社交。
头条(T)美团(M)滴滴(D),TMD被称为创业公司在BAT这样巨头下最大的成长界限,互联网也有阶层固化之势。
商战&混战
自2016起,阿里和腾讯的新零售之战开始布局, 什么是新零售?马云口中的新零售是什么?
美团推出打车、收购摩拜,商战:美团打车vs滴滴外卖
阿里收购饿了么、高德推出顺风车。
创业环境如此艰难,但总有人能破土而出。
想着想着居然睡着了....
2、服务员与厨师-前后端的区别
窗外下起了雨,滴答滴答...
周末了,本该很开心才对,小奈的心情却有点郁闷。坐在公交上,想着下午被Leader怼的话,心情十分不美丽。好不容易下班了,还下雨了,得找表哥好好倾诉。
大仁:哟哟哟,你这是怎么啦?
小奈:今天被Leader一顿怼…
大仁:为什么会被Leader怼呢?
小奈:是这样的,我方案今天上交的时候Leader说很多地方做得不对,前后端都没分清,微服务就更不用说了。
大仁:不要气馁,产品上有什么问题你可以问我呀
小奈:前后端怎么区分?后端写代码,前端负责显示?
大仁:这个前后端的区别,我画张图给你看看就知道了。
前后端区别
大仁:前端也要写代码的,后端写的代码没有界面显示,前端才有。
好比饭店一样,服务员是前端, 厨师是后端开发。服务员会给你端菜(看得到的前端),
但是做菜的是厨师(后端处理数据返给前端)。
小奈:那前后端怎么交互?
大仁:你看到那个窗口没有,服务员通过窗口拿菜,菜就是用户要的数据,窗口就是接口,前后端通过接口来协作,接口是后端的工作。
小奈:哦~那后端是不是做的比较多、比较累一点。
大仁:是的,厨师累一点。
大仁:不过今时不同往日,现在客人要求高了。要求服务员长得漂亮(界面好看) 还要会耍杂技(交互好)。这样说你可以理解么 ?
小奈:UI和UE有什么不一样么?
大仁:视觉设计(界面设计)ui像是服务员的衣服,ue (界面交互)就是点击这个按钮怎么跳转,ue像是服务员的上菜流程、手势等。
数据库就是神奇的物料仓库,厨师要做什么菜,需要从仓库里取, 取得时候会自动复制了一份,这个数据库以后再和你仔细讲。
小奈:哇,理解了,表哥好厉害呀。
大仁:总结起来的话,涉及界面展示的属于前端,当请求数据的时候,就是常见的增删改查,属于后端工作,后端需要提供好这些窗口,把菜放在那里,服务员就可以过去拿。
微服务vs单体应用
小奈:那微服务又是什么呢?
大仁:我再画2张图(产品经理就是爱画图)。
大仁:你们公司是搞电商的,电商后台系统比较大而全。基本上由用户管理、商品管理、订单管理、物流管理、采购管理、资产管理、内容管理等组成。而且项目早期研发的时候,都是都所有功能堆在一起,部署在一台服务器上。这种其实就是所谓的“单体应用”。
但是呢,随着业务发展,流量越来越大,这种单体应用的弊端就变得明显了。
怎么理解呢?单体应用之间各个模块互相依赖,如果某个模块挂了,就会影响其它模块。
或者做优惠活动的时候,对用户管理和优惠券这些模块压力较大,但是做负载均衡的时候其它模块也得上,浪费资源。
小奈:那怎么办?
大仁:其实把各个模块单独拎出来就好了。那里需要强化就强化那里。模块间依赖性也不会那么大。
小奈:那前期为什么不直接用微服务?
大仁:微服务其实比较花时间,但是各个服务拆分好后,对后续扩展和性能等的好处多多。所以很多创业项目前期都是单体应用,大公司除外。
为了感谢大仁悉心指导,小奈点了奶茶给大家喝,分奶茶的时候,看到大明一手鼠标一手键盘目不转睛地盯着屏幕。
2.1 初次见面-浏览器输入url后
小明来了
“叮咚叮咚”
初次见面
大仁:你去接待下我朋友,他叫小明,我们公司后端开发。
耳边突然传来一个甜美的声音。
小奈:你好,你是小明吧。
小奈:你好,我是小奈,表哥现在在忙,我来招待下你。
小奈:这是给你的茶,你先在这边坐下。
刷地一下从脸到耳根一阵通红,木住三秒后,
小明愣了下,然后双手接过茶
人物档案
原名黄小明,29岁,黑龙江某大学心理学专业,毕业后在五道口切过菜,某一天看懂犀牛书,从此进入前端,立志成为黑客。大仁公司后端主力开发。
小奈:你是做后端的吧,我有些技术问题可以请教你吗?
小明:可以,具体是什么问题呢?
小奈:我想知道你们平时敲的代码,是怎么变成网页的?怎么放到网上去的?
小明掏出了双肩包里面的笔记本
小明:你平时怎么看网页的?
小奈:在浏览器输入 www.hellojack.com 然后就可以了啊
小明:那你知道背后发生了什么么?我画个图给你看下。
小明:首先这里几个家伙:浏览器(360之类)、服务器(阿里云之类)、域名商(万网之类)、网页文件(index.html)、web环境盒子(Nginx之类)
小明:当你输入地址的时候,背后的事情是这样的。
浏览器打电话给域名商, hellojack.com 这个sb家地址在哪?
域名商告诉他ip地址,稍等,我给你转过去。
浏览器就把这个地址记到小本本上了,下次就不用问域名商了。
然后问服务器要东西了,你盒子里面那个东西呢?
服务器掏出盒子里的文件,切成很多小拼块,好的,我马上寄过去。
然后顺着网线传过去,传到浏览器这边。
浏览器就把拼块凭起来,展示出来了,你好你的文件。
小奈:每个域名都有IP地址地,之前我都不晓得IP跟域名有什么联系。
小明:1对1的,当然你也可以搬家。
小奈:好像懂了。
小明:那你看看我们是怎么实现的吧。
小明:我们首先就是写代码咯。长得像这样子,
<h1>hello jack</h1>
保存为 index.html 后,本地打开。
看到没,长这样子。
我启动个神奇的盒子,
var express = require('express');
var app = express();
app.set('view engine', 'html');
app.engine('html', require('ejs-mate'));
var server = app.listen(8081, function (req, res) {
console.log("hello world")
})
浏览器输入:localhost:8081
浏览器输入:127.0.0.1:8081
小奈:喔,原来这样子,那怎么输入 hellojack.com 来访问呢?
小明:对,接下来我要把它部署到阿里云上去,我之前买的。
但是域名这个我只买过 pmjishu.com 这个,我得去域名商那里买一下才行。
小奈:不用啦,我明白了。
小奈:实在太感谢你了,你好厉害喔。
只见小明又通红着脸
小明:不用客气,有什么不懂的问题随时请教”
今晚好美,月亮很好看。
2.2、小区与隔板间-机房和虚拟机
电脑主机vs虚拟机
小奈:一直不太明白,服务器是一个实体的机器吗?(类似一台主机)还是一个概念上的数据库?本地是指的是?
大仁:第一个问题,早期服务器就是一个实体的机器(物理机器)。但是虚拟机技术成熟后可以在一台物理机器上创建很多台虚拟机,所以这些虚拟机也可以作为服务器。类似A101和里面的隔板间。
第二个问题,我们常说的服务器(后台)是指后台程序+数据库,也就是主人+衣柜,衣柜是存储衣服(数据),主人是收拾、处理衣服的。你有钱可以一个住一间大房子,没钱或者觉得太大也可以隔出几个小板间租给别人。
目前常见的服务商是这样子做的,可能A101这间房间住了不同创业公司的后台。但是房间之间都是隔离的(技术成熟)。
第三个问题,其实我们自己也可以搭建服务器,要和运营商申请公网IP,一月好几千,那我们的电脑也就是服务器了。
云主机vs机房
- 机房:类似小区,由很多服务器组成
- 云主机:由多台服务器组成,共同处理计算数据。
机房,类似小区,由很多服务器组成。但是可能这些业主互不相识,也可能这一层住的都是老王家族。
云主机:类似别墅,老王家族住在别墅,他们之间是有关系的,一起合作处理一些大事。
3、世界之窗门票-账号与Token
世界之窗
终于周末了,真开心。
对小奈这种初入职场的人来说,还是很期待周末的。和表哥约好周末去世界之窗玩,放松之余,还要抓紧和表哥学习东西。
账号和门票一样
世界之窗外面是开放的,但是如果要进去里面的话,就需要买门票了。
小奈:这个门票是不是和账户密码一样?
大仁:是的
小奈:账号登陆是怎么实现的?
大仁:那要先给你简单讲下数据库。
数据库是什么?
数据:举个例子,班级里面的每个人,例如小周,他的各个字段:年级,性别、语数英等等,周杰伦的所有信息算是一条数据。
数据表:数据表就像一个excel表格,里面存了3年1班所有学生的数据。
数据库:数据库可以理解成一个文件夹,里面有很多excel表格,例如3年级所有班级(1、2、3班)的excel表格。
账号密码
大仁:这里的账号登陆和门票进场一样,但是稍微不同的是,它是永久性的,只要你不改密码/不被禁用。
Token则是凭据
“叮铃叮铃”
大仁:喂,小明啊,你也要来世界之窗么?
小明:是啊,但是我没门票,进不去啊。
大仁:我记得你是如花酒店会员是吧?
小明:是啊。
大仁:他们有和这个酒店合作,你试一下。
小明:你好,我是如花酒店的会员,能不能进去这里玩下。
检票员打电话给如花酒店,小明和酒店说了自己信息,酒店经理给了临时暗号:0007,你好可以了。
Token则更像是临时暗号,这个临时暗号是账号授权生成的,门票丢了得重新花钱买,token丢了重新操作下认证一个就可以了,因此token丢失的代价是可以忍受的。
Cookie 和 Session
这个账号密码,其实还有两个重要的概念,下回分解。
3.1 暗号和钥匙-Cookie和Session的区别
Cookie和Session的区别
小奈:表哥那个cookie和session有什么区别
大仁:记得上次了小明和你讲的故事么?, 在浏览器输入url背后发现的事。 2.1 初次见面-浏览器输入url后
大仁:上次输入的网址 www.hellojack.com ,其实完整的是 http://www.hellojack.com,前面有个http前缀,它是一个协议,无状态协议。
大仁:我来给你讲个故事吧。
http
很久很久以前(30年前,只有静态html的时候),有个发快递的人叫http。
偶尔有人打电话(无来电显示)向他买东西,他收到请求后,就会去中心仓库克隆一份这个东西,然后把货品塞到管道里,这样客人就收到了。
那时候工作很轻松,小日子过的挺舒服啊。
好景不常(社区、电商网站的出现),仓库里进了很多贵重和私密物品。
老板要求他记录订购贵重物品的客人,私密物品一定要鉴别客人身份。
暗号:cookie
但是没有来电显示啊,鬼知道谁定的,http就很苦恼了。
想了想,终于想到一个办法了。
以后客人打电话过来,我就给他个暗号。
终于可以记录了,但是又遇到了一个问题。
由于暗号比较简单,其他客人可以伪造。
档案袋和钥匙:session和session-id
http想了很久,最后和服务器协商,让服务器那边建立档案袋,并把钥匙给客人,下次叫客人把钥匙给他。之后客人都通过钥匙来打开档案袋,确定身份。如果打不开的话就证明错了。
我是邪恶的代码分割线
express 中的 cookie
express 在 4.x 版本之后,session管理和cookies等许多模块都不再直接包含在express中,而是需要单独添加相应模块。
var express = require('express');
// 首先引入 cookie-parser 这个模块
var cookieParser = require('cookie-parser');
var app = express();
app.listen(3000);
// 使用 cookieParser 中间件,cookieParser(secret, options)
app.use(cookieParser());
app.get('/', function (req, res) {
// 如果请求中的 cookie 存在 isVisit, 则输出 cookie
// 否则,设置 cookie 字段 isVisit, 并设置过期时间为1分钟
if (req.cookies.jack) {
console.log(req.cookies.jack);
res.send("welcome");
} else {
res.cookie('jack', 'content', {maxAge: 60 * 1000});
res.send("no cookie");
}
});
这里开发调试的时候用supervisor来启动,代码有改动,它会自动重启,避免不必要的手动重启工作。
新版本的开发者工具界面,在application里面可以看到cookies 这些存储
现在我们看到一个cookie名字为jack 内容为content的cookie就存储了,时间期限也有。
如果没有设置时间(maxage/expires),
那就是session cookie,
浏览器关闭的时候cookie就没了。
session
cookie 虽然很方便,但是使用 cookie 有一个很大的弊端,cookie 中的所有数据在客户端就可以被修改,数据非常容易被伪造,那么一些重要的数据就不能存放在 cookie 中了,而且如果 cookie 中数据字段太多会影响传输效率。为了解决这些问题,就产生了 session,session 中的数据是保留在服务器端的。
session 的运作通过一个session_id来进行。session_id通常是存放在客户端的 cookie 中,比如在 express 中,默认是connect.sid这个字段,当请求到来时,服务端检查 cookie 中保存的 session_id 并通过这个 session_id 与服务器端的 session data 关联起来,进行数据的保存和修改。
这意思就是说,当你浏览一个网页时,服务端随机产生一个 1024 比特长的字符串,然后存在你 cookie 中的connect.sid字段中。当你下次访问时,cookie 会带有这个字符串,然后浏览器就知道你是上次访问过的某某某,然后从服务器的存储中取出上次记录在你身上的数据。由于字符串是随机产生的,而且位数足够多,所以也不担心有人能够伪造。伪造成功的概率比坐在家里编程时被邻居家的狗突然闯入并咬死的几率还低。
session 可以存放在 1)内存、2)cookie本身、3)redis 或 memcached 等缓存中,或者4)数据库中。线上来说,缓存的方案比较常见,存数据库的话,查询效率相比前三者都太低,不推荐;cookie session 有安全性问题,下面会提到。
express 中操作 session 要用到express-session(https://github.com/expressjs/session) 这个模块,主要的方法就是session(options),其中 options 中包含可选参数,主要有:
name: 设置 cookie 中,保存 session 的字段名称,默认为connect.sid。
store: session 的存储方式,默认存放在内存中,也可以使用 redis,mongodb 等。express 生态中都有相应模块的支持。
secret: 通过设置的 secret 字符串,来计算 hash 值并放在 cookie 中,使产生的 signedCookie 防篡改。
cookie: 设置存放 session id 的 cookie 的相关选项,默认为
(default: { path: '/', httpOnly: true, secure: false, maxAge: null })
genid: 产生一个新的 session_id 时,所使用的函数, 默认使用uid2这个 npm 包。
rolling: 每个请求都重新设置一个 cookie,默认为 false。
resave: 即使 session 没有被修改,也保存 session 值,默认为 true。
1) 在内存中存储 session
express-session默认使用内存来存 session,对于开发调试来说很方便。
var express = require('express');
// 首先引入 express-session 这个模块
var session = require('express-session');
var app = express();
app.listen(5000);
app.use(cookieParser('jack2016'));
//解析cookie secret为‘jack2016’的cookie,可不可以不写secret?不写会报错
}));
// 按照上面的解释,设置 session 的可选参数
app.use(session({
secret:'jack2016',
// 建议使用 128 个字符的随机字符串,这里不写secret的话cookie存储的是不加密的sessionid
name:'jacks', //cookie名字,这里cookie存的内容是用secret加密的sessionid, cookie: {maxAge:60*2000},//cookie设置,maxAge设置时间好像受到限制,太小直接没效,设置的够大无论是60*60还是60*60*24*12好像都是固定的4小时,这里有点疑惑。
}));
/* GET home page. */
router.get('/',function(req,res,next) {
console.log(req.sessionID,req.cookies.jack,req.signedCookies.jack);
res.render('index',{title:'Express'});
});