【22/04】Chrome 里的请求报错 “CAUTION: Provisional headers are shown“ 是什么意思?
问题1: Chrome 里的请求报错 “CAUTION: Provisional headers are shown” 是什么意思?
原解决方案:
解决:后端对 OPTIONS 请求进行了判断,不需要处理任何直接返回,速度快了很多,也就没有再出现上面的问题了。
问题2:TypeError: Cannot read properties of undefined (reading ‘username’)
期间还遇到一个问题, 就是一直报如下错误
TypeError: Cannot read properties of undefined (reading 'username')
将 req.body打印出来为undefined, 所以报上述错误. 但明明表单数据有post给服务器… 后面发现 req.body: 通常用来解析POST请求中的数据, 不是nodejs默认提供的,需要载入中间件body-parser中间件才可以使用. 即没有注册中间件, 请求体为服务器端无法进行解析的MIME类型, 此外, 官方也给出了解释
Express官方文档:
req.body contains key-value pairs of data submitted in the request body. By default, it is undefined, and is populated when you use body-parsing middleware such as express.json() or express.urlencoded().
所以以下两种方案, 可以解决问题
//方案1
// For parsing application/x-www-form-urlencoded
app.use(express.urlencoded({extended: true
}))
//方案2
// 载入中间件body-parser中间件
const bodyParser = require('body-parser')
app.use(bodyParser.urlencoded({extended: false
}))
总结: 使用中间件, 请求体默认格式为字符串application/x-www-form-urlencoded, 可以添加express.urlencoded解析请求体, 也可以使用解析post表单数据的中间件body-parser
问题3: 静态资源托管无效
还发现我用了一个很傻的方式去渲染页面, 就是用Node.js内置模块去读取html页面的内容作为res.send响应体, 但实际上只需要将所有页面都放到pages文件夹下, 使用内置中间件express.static托管静态资源即可. 但也出现了一个很傻的bug:
app.use(express.static('./pages'))
改成下面写法, 就完全正确了, 可以url正常访问
app.use(express.static('pages'))
还会遇到一个问题: Node.js问题——req.session.user 与浏览器刷新.
我的代码里, 用户登录成功后就跳转到首页, 发送一个get请求, 调用api/username, 获取session存储的username, 然后在首页上方显示: username, 欢迎您. 但打印req.session居然没有username这个属性, 我悟了, 难道session不是每个页面共享的吗??? 我前脚在登录页设置了session.islogin属性, 后脚在首页就session.islogin undefined…
然后吧, 我发现我智障了, 我是用postman测试的api/username, 当然不存在session.islogin…
session确实就是整个站点共享的啊, 这也是session解决http无状态性的根本… 至于页面刷新就不存在session.islogin, 那是因为session的存活时间太短了, 刷新后就生成了新的session了, 去掉session里设置cookie的Max-Age
补充知识点: 原生node中怎么获取get/post请求参数
在这里在补充一个知识点, 部分参考原生node中怎么获取get/post请求参数:
- req.body: 通常用来解析POST请求中的数据, req.body不是nodejs默认提供的,需要载入中间件body-parser中间件才可以使用
- req.query: 由nodejs默认提供,无需载入中间件,此方法多适用于GET请求,解析GET请求中的参数, 包含在路由中每个查询字符串参数属性的对象,如果没有则为{}
- req.params: nodejs默认提供,无需载入其他中间件, req.params包含路由参数(在URL的路径部分),而req.query包含URL的查询参数(在URL的?后的参数)。
- req.session: 当express-session中间件配置成功后, 可以使用req.session来访问和使用session对象, 从而存储用户信息
- req.user: 当express-jwt中间件配置成功后, 可以使用 req.user 获取用户信息,并使用 data 属性将用户信息发送给客户端
问题4: 又写了JWT鉴权, 但读取req.user一直是undefined…
session是对cookie的补充, JWT是对session的补充, 安全性层层拔高, 任何一个新事物都是解决某一问题, 又产生另一问题, 选择何种方式进行鉴权取决于 你的侧重点是什么.
因为session还是使用了cookie存储SessionID, 存在跨域问题, 需要很多额外的配置, 同时session占用服务器的内存, 所以需要redis多个服务器共享该session, 把身份认证这件事又搞麻烦了. 于是诞生了JWT, 使用了H5新增的Web Storage, 服务器将身份认证信息加密给客户端存储, 又解决了服务器内存占用的问题, 同时没使用cookie跨域也解决了. 但因为添加了Authorization新的请求头, 所以又会产生预检请求, 服务器端要做相应的处理…
写JWT鉴权的代码, 需要准备以下材料: 2个中间件, 一个负责用户身份信息加密, 一个负责客户端发来的JWT解析为json, 还要定义秘钥(就是一个字符串).
参考代码又不全, 自己写了一个下午, 终于把思路理清楚, 踩的坑也解决了, 对JWT的理解也更深了, 所以就不一一展开对问题解释分析了, 直接将完整, 可运行代码粘在下面. 亲测有效.
JWT的express框架身份认证完整代码
// 1.导入用于生成JWT字符串的包
const jwt = require('jsonwebtoken')
// 2.导入用于将客户端发送的JWT字符串,解析还原为JSON对象的包
const expressJWT = require('express-jwt')
// 3. 定义secret秘钥, 保证JWT字符串的安全性
const express = require('express')
// 创建服务器实例
const app = express();
//允许跨域资源享用
const cors = require('cors');
app.use(cors())//解析post表单数据的中间件
const bodyParser = require('body-parser')
app.use(bodyParser.urlencoded({extended: false
}))
//2. 定义secret秘钥
const secretKey = 'huangrong'//注册将 JWT 字符串解析还原成 JSON 对象的中间件
app.use(expressJWT({secret: secretKey,algorithms: ["HS256"],requestProperty: "auth", //res.auth.username就可以拿到用户名了, 默认是usercredentialsRequired: false, //是否允许未认证用户访问getToken: function fromHeaderOrQuerystring(req) { //验证tokenif (req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Bearer') {return req.headers.authorization.split(' ')[1];} else if (req.query && req.query.token) {return req.query.token;}return null;}
}).unless({ //肯定登录页面是不用JWT鉴权的, 不然就是死循环了path: [{url: '/login', method: ['GET', 'POST']},[/^\/api\//] //调用api也不用JWT健全]
}));app.use(express.static('pages')) //托管静态资源, 我自己就做了2个页面, index和login//登录接口
app.post('/api/login', (req, res) => {//需要载入中间件body-parser中间件才可以使用req.bodyconst userinfo = req.bodyconsole.log(userinfo);if (userinfo.username !== 'admin' || userinfo.password !== '000000') {return res.send({status: 1,msg: '登陆失败!'})}// 用户成功登录后, 生成JWT字符串, 通过token属性响应给客户端//token: 调用 jwt.sign()生成JWT字符串, 三个参分别为 用户信息对象, 加密秘钥, 配置对象:当前 token 的有效期 const tokenStr = jwt.sign({username: userinfo.username}, secretKey, {expiresIn: '1d' //token过期时间, 好像比较难手动注销JWT, 具体自己查一下})res.send({status: 0,msg: '登陆成功!',token: tokenStr //生成的token加密字符串, 三部组成: header + payload + Signature, 只有中间是真正信息})
})//这是一个有权限的API接口, 为什么说有权限, 是因为JWT验证成功, 服务器才能获取req,auth, 因为这个路径不在unless里
app.get('/admin/getinfo', (req, res) => {//使用 req.user 获取用户信息,并使用 data 属性将用户信息发送给客户端console.log(req.auth); res.send({status: 1,msg: '获取用户信息成功',data: req.auth //要发送给客户端的用户信息})
})//6. 使用全局错误处理中间件, 捕获JWT失败后产生的错误, 建议测试代码, 不要用, 完全没办法定位错误了!!!!
// app.use((err, req, res, next) => {// if (err.name == 'UnauthorizedError') {// return res.send({// status: 401,
// msg: '无效的token'
// })
// }
// next();
// // res.send({// // status: 500,
// // msg: '未知的错误'
// // })
// })app.listen(3000, () => {console.log('Express server running at http://127.0.0.1:3000')
})
Session的express框架身份认证完整代码
const express = require('express');
const app = express();
// 1. 导入session中间件
var session = require('express-session')
const cors = require('cors');// 2. 配置Session中间件 session不要写在路由的下方
app.use(session({secret: 'keyboard cat', //secret可以为任意字符串resave: false, //固定写法saveUninitialized: true, //固定写法cookie: {maxAge: 1000 * 30 * 3}
}))app.use(cors())
// 托管静态资源
app.use(express.static('pages'))
// For parsing application/x-www-form-urlencoded 解析post提交的表单数据
app.use(express.urlencoded({extended: false
}))//3. 向session中存数据
//当express-session中间件配置成功后, 可以使用req.session来访问和使用session对象, 从而存储用户信息
app.post('/api/login', function (req, res) {// res.json(req.body)console.log(req.body);if (req.body.username !== 'admin' || req.body.password !== '000000') {return res.send({status: 1,msg: '登陆失败'})}//只有成功配置express-session中间件, 才有req.session属性req.session.user = req.bodyreq.session.islogin = trueconsole.log(req.session)res.send({status: 0,msg: '登录成功'})
})
//获取用户姓名的接口
app.get('/api/username', (req, res) => {console.log(req.session);//判断用户是否登录if (!req.session.islogin) {return res.send({status: 1,msg: 'fail'})}res.send({status: 0,massage: 'success',username: req.session.user.username})
})
//退出登录接口
app.post('/api/logout', (req, res) => {req.session.destroy()res.send({status: 0,msg: '退出登录成功'})
})app.listen(3000, () => {console.log('CORS-enabled web server listening on port 3000');
})
【22/04】Chrome 里的请求报错 “CAUTION: Provisional headers are shown“ 是什么意思?相关推荐
- Provisional headers are shown in Chrome network tab
Created by Wang, Jerry on Oct 15, 2015 细心的同学应该留意到,新版开发者工具的 Network 面板中,某些请求头后面会跟着下面这行文字: 截图是访问 http: ...
- Chrome v39 问题 Provisional headers are shown
1,网站突然访问不到图片了. 发现: Provisional headers are shown 解决:删除chrome ,然后重启chrome即可. 第一个 http 请求实际上根本没有产生,对应的 ...
- Chrome插件请求数据时 请求报错(blocked:mixed-content)
Chrome插件请求数据时请求报错(blocked:mixed-content) 问题原因 解决方案 方案1:配置https 方案1:使用background.js请求http 问题原因 问题原因是我 ...
- 请求报错No route to host (Host unreachable)
请求报错No route to host (Host unreachable); nested exception is java.net.NoRouteToHostException: No rou ...
- ajax jsonp请求报错not a function的解决方案
ajax jsonp请求报错not a function的解决方案 参考文章: (1)ajax jsonp请求报错not a function的解决方案 (2)https://www.cnblogs. ...
- python https请求报错:SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] 解决方法
python爬虫,使用requests库发送https请求报错:SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] 解决方法: imp ...
- Here Document和Expect概述(免交互,变量设定,控制,注释,)(shell里使用EOF报错)
文章目录 Here Document概述 Here Document使用注意事项 Here Document免交互 Here Document变量设定 Here Document格式控制 Here D ...
- ajax请求接口连不上会报错吗_服务端有异常, 导致: Ajax 请求报错 net::ERR_INCOMPLETE_CHUNKED_ENCODING...
服务端有异常, 导致: Ajax 请求报错 net::ERR_INCOMPLETE_CHUNKED_ENCODING 但是,这个 Ajax Http 接口使用浏览器可以直接返回.表明,Ajax 的 G ...
- 【亲测成功】Ubuntu18.04升级GLIBC2.27——解决报错:ibc.so.6: version `GLIBC_2.28‘ not found
[亲测成功]Ubuntu18.04升级GLIBC2.27--解决报错:/lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.28' not found 事 ...
- ubuntu16.04挂载三星T5移动硬盘报错
ubuntu16.04挂载三星T5移动硬盘报错 首先查看硬盘信息 sudo fdisk -l | grep NTFS 例如输出如下信息: /dev/sdd1 2048 97677021 9767680 ...
最新文章
- Mac下搭建solr搜索引擎与PHP扩展开发(上)
- 五种常见的 PHP 设计模式
- linux安装apache的纠结过程
- 成对的交换链表的节点 Swap Nodes in Pairs
- linux系统常用快捷键,文件类型,后缀名,语言修改,转义
- 用 SOLID 原则保驾 React 组件开发
- DE19 Introduction to the Laplace Transform
- [转载] Python之Numpy模块中的方法详解
- android listview 只加载显示的图片大小,Android ListView只加载当前屏幕内的图片(解决list滑动时加载卡顿)...
- Delphi XE 操作sqlite数据库
- 《金字塔原理》读书笔记
- 微信小程序:收款码三合一制作微信小程序源码下载多模板选择
- pdf打印机如何加密pdf文件?
- linux用ping命令测试网速,Linux通过终端测试网速
- 7-11 秋天的第一杯奶茶 (20 分)
- CUDA学习笔记(三)——共享内存
- 使用Unity实现时光倒流
- [Contrastive Learning] Improving Contrastive Learning by Visualizing Feature Transformation
- Unity - 画质设置
- ffmpeg与ffdshow的关系
热门文章
- 电路设计之8:MOS管驱动设计
- 力扣36.有效的数独
- 周董演唱会为什么总是抢不到票?教你用Python做一个自动抢票脚本
- 荣耀5G,三刀拍案惊奇
- 神经机器翻译中有用的技巧
- 中文语音合成TTS (TensorFlowTTS)免费API资源及DEMO
- 语音合成 TTS 相关的一些总结
- 计算机硬盘上的文件打不开,电脑硬盘打不开怎么办
- Spring Transaction : TransactionInterceptor
- c语言表达式判断语法错误题,大连理工大学C语言模拟题机房题库单选、判断、填空(分章节_共十一章)...