900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > 【22/04】Chrome 里的请求报错 “CAUTION: Provisional headers are shown“ 是什么意思?

【22/04】Chrome 里的请求报错 “CAUTION: Provisional headers are shown“ 是什么意思?

时间:2021-07-13 11:05:06

相关推荐

【22/04】Chrome 里的请求报错 “CAUTION: Provisional headers are shown“ 是什么意思?

问题1: Chrome 里的请求报错 “CAUTION: Provisional headers are shown” 是什么意思?

原回答:

情况:前后端分离项目中接口请求需要进行跨域处理,跨域请求的话浏览器会自动发出一个 OPTIONS 请求,然后返回允许该域名进行请求的相关信息后会再发出 GET 或者 POST 请求。我在 axios 的初始化处统一设置了 timeout 时间为 5s,然后由于后端人员没有针对 OPTIONS 请求进行单独处理,在 OPTIONS 请求时也进行了业务代码的执行,导致请求返回时间过长,有时候超过了 timeout 时间,因此后面的 GET 或者 POST 请求就没有发送成功,出现了 provisional headers are shown 的问题。

原解决方案:

解决:后端对 OPTIONS 请求进行了判断,不需要处理任何直接返回,速度快了很多,也就没有再出现上面的问题了。

本人出现问题:

也是前后端分离的开发模式, 打算发一个ajax请求, 测试自己写的express后端API, 实现session鉴权和状态登录, 但一直报错, 所以和上面这个问题较为相似. (自己写的原生代码就是垃圾, 第二天用jQuery库写Ajax, 各种bug都消失了…真的是佛了)

问题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');})

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。