nodejs+mongodb笔记------第四章(HTTP请求、express框架、路由、中间件)

GET请求与POST请求

前言

HTTP请求,最初设定了八种方法(也称为“动作”)。这八种方法本质上没有任何区别。只是让请求,更加有语义而已。
八种方法分别为:OPTIONS、HEAD、GET、POST、PUT、DELETE、TRACE、CONNECT
这八种方法最终经过“岁月沉淀”后,常用的只有两种,即:GET和POST

GET

1. 含义:从指定的资源获取数据(一种“索取”的感觉)。
2. 什么时候使用GET请求较为合适?
    (1)单纯获取数据的时。
    (2)请求中不包含敏感数据时。

POST

1.含义:向指定的资源提交要被处理的数据(一种“交差”的感觉)。
2.什么时候使用POST请求较为合适?
    (1)传送相对敏感数据时。
    (2)请求的结果有持续性的副作用,例如:传递的数据要作为数据源写入数据库时。
备注:使用了POST不代表的绝对的安全。

常见的GET请求:

1.浏览器地址栏输入网址时(浏览器请求网页时时GET请求,且不可更改)
2.可以请求外部资源的html标签,例如:<img> <a> <link> <script>
3.发送Ajax时明确指出了使用GET请求
4.form表单提交时没有指明方式,默认使用GET

常见的POST请求:

1.发送Ajax时明确指出了使用POST方式
2.使用第三方发送Ajax请求库时明确指出用POST时
3.form表单提交时明确指出使用POST方式

二者的区别

express服务器

//1.引入express
let express = require('express')

//2.创建app服务对象
let app = express()
//隐藏服务器的具体实现
app.disable('x-powered-by')

//3.设置路由(这里配置的是后端路由)   路由可以理解为:key-value的组合,响应路由是一个匹配的过程。

//根路由
app.get('/',(request,response)=>{
  response.send('<h2>我是主界面</h2>')
})

//一级路由
app.get('/meishi',(request,response)=>{
  /*
  什么样的请求能交给这个回调函数处理?
      1.发送的请求必须为GET请求
      2.访问的URL中关键词是meishi
  备注:使用request.query只能获取查询字符串参数
  */
  console.log(request.query);
  response.send('<h2>我是美食界面</h2>')
})

//二级路由
app.get('/meishi/huoguo',(request,response)=>{
  /*
  什么样的请求能交给这个回调函数处理?
      1.发送的请求必须为GET请求
      2.访问的URL中关键词是meishi
  */
  response.send('<h2>我是美食---火锅界面</h2>')
})

app.post('/demo',(request,response)=>{
  /*
  * 备注:使用request.body能够获取POST请求过来的请求体中的参数,但是需要借助一个中间件。
  * */
  console.log(request.body);
  response.send('你发来的post请求,我收到了,这是我给你的响应')
})

app.get('/demo',(request,response)=>{
  response.send('你发来的get请求,我收到了,这是我给你的响应')
})

//4.绑定端口监听
app.listen(3000,(err)=>{
  if (!err) console.log('服务器启动成功了!')
  else console.log(err)
})

http协议

  • http协议是什么:超文本传输协议(属于应用层协议)
  • 特点:无状态,现在cookie解决了无状态的问题(早期网页开发时,用cookie解决,现在是cookie和session配合使用)
  • 作用:规定了服务器和客户端传递信息的规则(统称为报文,分为:请求报文、响应报文。)
  • 版本:
    • http 1.0 (老版本) ---------- 不支持长连接
    • http 1.1 (主流版本)--------- 优点:支持长连接,弊端:同时发送资源的数量过小。
    • http 2.0 (最新版) ---------- 同时发送资源的数量稍有提升。
  • 报文(请求报文、响应报文)的组成:
    1.报文首行
    2.报文头
    3.空行(仅仅作为一个分割)
    4.报文体

http报文与http状态码

1.分析GET请求报文(给服务器看的)

GET http://localhost:3000/meishi HTTP/1.1
Host: localhost:3000
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36
DNT: 1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
空行
空行

报文首行

GET http://localhost:3000/meishi HTTP/1.1
    -请求类型 协议名://主机名:端口号/路由关键词 使用协议的版本

报文头

Host: localhost:3000
      --访问的主机名(地址,仅仅包含主机名+端口号)
      --防盗链、广告计费
Connection: keep-alive
      --告诉服务器,浏览器端支持长连接
Upgrade-Insecure-Requests: 1
      --告诉服务器,浏览器端支持https协议
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36
      --用户代理,告知服务器你的浏览器内核以及品牌,早期的时候用于判断用户的浏览器是哪一个品牌,现在不可用了。
DNT: 1
      --禁止跟踪,告知服务器禁止跟踪,并不是写了该字段服务器就一定遵守。
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
      --告知服务器浏览器能接受的文件类型,q是资源的优先级,取值范围是0-1,1的权限最高,默认是1
Accept-Encoding: gzip, deflate, br
      --告诉服务器浏览器能支持的文件压缩格式
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
      --告诉服务器,浏览器能够接受的语言

空行

报文体

GET 请求没有报文体

2.分析POST请求报文(给服务器看的)

POST http://localhost:3000/demo HTTP/1.1
Host: localhost:3000
Connection: keep-alive
Content-Length: 16
Cache-Control: max-age=0
Origin: http://localhost:63342
Upgrade-Insecure-Requests: 1
DNT: 1
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng, */ *;q=0.8,application/signed-exchange;v=b3
Referer: http://localhost:63342/node/day04/1.express%E6%9C%8D%E5%8A%A1%E5%99%A8/demo.html?_ijt=tjfnb0cpos62ql8umjmm9v24ve
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
Cookie: Webstorm-9af2238=09820128-3adb-43e4-8242-a6f65c9e523a

name=kobe&age=18

报文首行

POST http://localhost:3000/demo HTTP/1.1
    -

报文头

Host: localhost:3000
    --访问的主机名(地址,仅仅包含主机名+端口号)
Connection: keep-alive
    --告诉服务器,浏览器端支持长连接
Content-Length: 16
    --请求体的长度
Cache-Control: max-age=0
    --用于控制强缓存
Origin: http://localhost:63342
    --当前所处位置(主机位置+端口位置)
Upgrade-Insecure-Requests: 1
    --告诉服务器,浏览器端支持https协议
DNT: 1
    --禁止跟踪,告知服务器禁止跟踪,并不是写了该字段服务器就一定遵守。
Content-Type: application/x-www-form-urlencoded
    --标识该请求是来自于一个form表单,并且以urlencoded形式进行编码
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36
    --用户代理,告知服务器你的浏览器内核以及品牌,早期的时候用于判断用户的浏览器是拿一个品牌,现在不可用了。
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,* / *;q=0.8,application/signed-exchange;v=b3
    --告知服务器浏览器能接受的文件类型,q是资源的优先级,取值范围是0-1,1的权限最高,默认是1
Referer: http://localhost:63342/node/day04/1.express%E6%9C%8D%E5%8A%A1%E5%99%A8/demo.html?_ijt=tjfnb0cpos62ql8umjmm9v24ve
    --在当前url下发出去的请求,是一个完整url,也可以做防盗链、同时也可以做广告计费
Accept-Encoding: gzip, deflate, br
    --告诉服务器浏览器能支持的文件压缩格式
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
    --告诉服务器,浏览器能够接受的语言
Cookie: Webstorm-9af2238=09820128-3adb-43e4-8242-a6f65c9e523a
    --Webstorm帮你“种”的一个cookie

空行

报文体

name=kobe&age=18
    --携带过去的数据,以urlencoded进行编码

3.分析响应报文(给浏览器看的)

HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: text/html; charset=utf-8
Content-Length: 27
ETag: W/"1b-q8c2w67PUz7P4t0CNbDw9xqw6bo"
Date: Tue, 23 Jul 2019 06:20:18 GMT
Connection: keep-alive

<h2>我是美食界面</h2>

报文首行

HTTP/1.1 200 OK
协议名/协议版本 状态码

报文头

X-Powered-By: Express
    -服务器所使用的框架
Content-Type: text/html; charset=utf-8
    -告诉浏览器解析文件的方式;文件编码方式
Content-Length: 27
    -响应体的长度
ETag: W/"1b-NFYx6TA4AihYceTsWYDlBLJferg"
    -协商缓存(资源唯一标识)
Date: Tue, 23 Jul 2019 06:20:18 GMT
    -日期
Connection: keep-alive
    -告诉浏览器,服务器支持长连接

空行

报文体

<h2>我是美食界面</h2>

4.http状态码(服务器给客户端的东西)

作用:

  • 告诉客户端,当前服务器处理请求的结果

http状态码的分类

  • 1xx : 服务器已经收到了本次请求,但是还需要进一步的处理才可以。
  • 2xx : 服务器已经收到了本次请求,且已经分析、处理等........最终处理完毕!
  • 3xx : 服务器已经接收到了请求,还需要其他的资源,或者重定向到其他位置,甚至交给其他服务器处理。
  • 4xx :一般指请求的参数或者地址有错误, 出现了服务器无法理解的请求(一般是前端的锅)。
  • 5xx :服务器内部错误(不是因为请求地址或者请求参数不当造成的),无法响应用户请求(一般是后端人员的锅)。

常见的几个状态码

  • 200 :成功(最理想状态)
  • 301 :重定向,被请求的旧资源永久移除了(不可以访问了),将会跳转到一个新资源,搜索引擎在抓取新内容的同时也将旧的网址替换为重定向之后的网址;
  • 302 :重定向,被请求的旧资源还在(仍然可以访问),但会临时跳转到一个新资源,搜索引擎会抓取新的内容而保存旧的网址。
  • 304 :请求资源重定向到缓存中(命中了协商缓存)。
  • 404 :资源未找到,一般是客户端请求了不存在的资源。
  • 500 :服务器收到了请求,但是服务器内部产生了错误。
  • 502 :连接服务器失败(服务器在处理一个请求的时候,或许需要其他的服务器配合,但是联系不上其他的服务器了)。

经典面试题

问题:从用户输入URl按下回车,一直到用户能看到界面,期间经历了什么?

一、DNS解析(缓存):
    1.找浏览器DNS缓存解析域名
    2.找本机DNS缓存:ipconfig/displaydns > C:/dns.txt
    3.找路由器DNS缓存
    4.找运营商DNS缓存(百分之80的DNS查找,到这一步就结束)
    5.递归查询,(最不愿意看到的事,查询的是全球13台DNS根服务器中的一个)

二、进行TCP(协议)连接,三次握手(根据上一步请求回来的ip地址,去联系服务器)
    第一次握手:由浏览器发给服务器,我想和你说话,你能“听见”嘛?
    第二次握手:由服务器发给浏览器,我能听得见,你说吧!
    第三次握手:由浏览器发给服务器,好,那我就开始说话。

三、发送请求(请求报文)

四、得到响应(响应报文)

五、浏览器开始解析html
      --预解析:将所有外部的资源,发请求出去
      --解析html,生成DOM树
      --解析CSS,生成CSSOM树
      --合并成一个render树
      --js是否操作了DOM或样式
          --有:进行重绘重排(不好,1.尽量避免;2.最小化重绘重排)
          --没有:null
      --最终展示界面

六、断开TCP连接,四次挥手(确保数据的完整性)
      第一次挥手:由浏览器发给服务器,我的东西接受完了,你关闭吧。
      第二次挥手:由服务器发给浏览器,我还有一些东西没接收完,你等一会,我接收好了我告诉你
      第三次挥手:由服务器发给浏览器,我接收完了,你断开吧
      第四次挥手:由浏览器发给服务器,好的,那我断开了。

路由的使用

//1.引入express
let express = require('express')

//2.创建app服务对象
let app = express()

//3.设置路由
//根路由
app.get('/',(request,response)=>{
  /*
  * request:
  *   request.query 获取查询字符串的参数,拿到的是一个对象
  *   request.params    获取参数路由的参数,拿到的是一个对象
  *   request.body  获取post请求体,拿到的是一个对象(要借助一个中间件)
  *   request.get(xxxx) 获取请求头中指定key对应的value
  *
  * response:
  *     response.send() 给浏览器做出一个响应
        response.end()  给浏览器做出一个响应(不会自动追加响应头,容易乱码)
        response.download() 告诉浏览器下载一个文件(相对路径)
        response.sendFile() 给浏览器发送一个文件(绝对路径)
        response.redirect() 重定向到一个新的地址(url)
        response.set(header,value)  自定义响应头内容
        response.get()  获取响应头指定key对应的value
        res.status(code)    设置响应状态码

  * */
  //console.log(request.query);
  //console.log(request.get('host'))
  response.set('demo',123)
  console.log(response.get('demo'));
  response.send('ok')
  //response.download('./public/队列.jpg')
  //response.sendFile(__dirname+'/public/demo.html')
  //response.sendFile(__dirname+'/public/demo.zip')
  //response.redirect('https://www.baidu.com')
})

//一级路由
app.get('/meishi',(request,response)=>{
  console.log(request.params);
  response.send('我是美食路由的反馈')
})

//二级路由
app.get('/meishi/huoguo',(request,response)=>{
  console.log(request.params);
  response.send('我是美食--火锅路由的反馈')
})


//参数路由
app.get('/meishi/:id',(request,response)=>{
  console.log(request.params);
  response.send('我是参数路由的反馈')
})

//4.绑定端口监听
app.listen(3000,(err)=>{
  if (!err) console.log('服务器启动成功了')
  else console.log(err)
})

中间件

/*
 中间件:
     概念:本质上就是一个函数,包含三个参数:request、response、next

 作用:
        1)  执行任何代码。
        2)  修改请求和响应对象。
        3)  终结请求-响应循环。
        4)  调用堆栈中的下一个中间件或路由。
  分类:
        1)  应用(全局)级中间件(过滤非法的请求,例如防盗链)
              --第一种写法:app.use((request,response,next)=>{}
              --第二种写法:使用函数定义
        2)  第三方中间件(通过npm下载的中间件,例如body-parser)
              --app.use(bodyParser.urlencoded({extended:true}))
        3)  内置中间件(express内部封装好的中间件)
              --app.use(express.urlencoded({extended:true}))
              --app.use(express.static('public'))
        4)  路由器中间件 (Router)
              --后面会说
   备注:
        1.在express中,定义路由和中间件的时候,根据定义的顺序(代码的顺序),将定义的每一个中间件或路由,
        放在一个类似于数组的容器中,当请求过来的时候,依次从容器中取出中间件和路由,进行匹配,如果匹配
        成功,交由该路由或中间件处理。
        2.对于服务器来说,一次请求,只有一个请求对象,和一个响应对象,其他任何的request和response都是对二者的引用。
 */

let express = require('express')
let bodyParser = require('body-parser')

let app = express()
//使用body-parser中间件解析post请求过来的请求体参数为一个对象,随后挂载到request上
//app.use(bodyParser.urlencoded({extended:true}))

//内置中间件 ---- 解析post请求过来的请求体参数为一个对象,随后挂载到request上
app.use(express.urlencoded({extended:true}))

//内置中间件 ---- 暴露静态资源
app.use(express.static('public'))

//全局中间件的第一种写法
/*app.use(function (request,response,next) {
 if(request.get('host') !== 'localhost:3000'){
   response.send('禁止发送非法请求')
 }else{
   next() //让下一个匹配的路由或中间件生效
 }
})*/

//全局中间件的第二种写法
function myMiddleWare(request,response,next) {
  if(request.get('host') !== 'localhost:3000'){
    response.send('禁止发送非法请求')
  }else{
    request.demo = 123
    next() //让下一个匹配的路由或中间件生效
  }
}

app.get('/',myMiddleWare,(request,response)=>{
  console.log(request.demo);
  response.send('我是根路由的响应')
})

app.get('/meishi',(request,response)=>{
  response.send('我是美食路由的响应')
})

app.post('/demo',(request,response)=>{
  console.log(request.body)
  response.send('post请求得到回应了')
})

/*app.get('/index',(request,response)=>{
  response.sendFile(__dirname+'/public/index.html')
})*/


app.listen(3000,(err)=>{
  if(!err)console.log('ok')
  else console.log(err)
})
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350