文章链接:express的使用(二) response的常用类型,欢迎关注订阅号,提供更多技术文章
看前提示
在开发中,很多时候我们不需要写中间件,比较多的时候是做一个api接口,但是api接口的类型有很多,比如文章下载,重定向等,对我们开发而言,优先级比中间件还有cookie高,所以就先写一篇关于返回体的。
本文很多是照本宣科的,在官网很多时候会找到,只是整理下,就不一一粘贴原文的描述
本篇依旧是废话连篇,因为对很多新手来说,接触express的时候,都只是返回一个hello world。但是很多时候一个文本的hello world并不能满足我们的需求,所以才会有萌生水一篇关于response的想法,理所当然的,我也不会那么简单的列出几个api,而是从下面几个方向。去列出一些常用的api
依赖版本
"pug": "^3.0.2","cookie-parser": "^1.4.6"
关于cookie
什么是cookie
HTTP Cookie(也叫 Web Cookie 或浏览器 Cookie)是服务器发送到用户浏览器并保存在本地的一小块数据。浏览器会存储 cookie 并在下次向同一服务器再发起请求时携带并发送到服务器上。通常,它用于告知服务端两个请求是否来自同一浏览器——如保持用户的登录状态。Cookie 使基于无状态的 HTTP 协议记录稳定的状态信息成为了可能。
Cookie 主要用于以下三个方面:会话状态管理 如用户登录状态、购物车、游戏分数或其他需要记录的信息
个性化设置 如用户自定义设置、主题和其他设置
浏览器行为跟踪 如跟踪分析用户行为等
Cookie 曾一度用于客户端数据的存储,因当时并没有其他合适的存储办法而作为唯一的存储手段,但现在推荐使用现代存储 API。由于服务器指定
Cookie 后,浏览器的每次请求都会携带 Cookie 数据,会带来额外的性能开销(尤其是在移动环境下)。新的浏览器 API
已经允许开发者直接将数据存储到本地,如使用 Web storage API(localStorage 和 sessionStorage)或
IndexedDB 。
简单来说,cookie现在已经废了,但是不排除有的网站还在使用cookie存储一些数据,所以我们还是得看一下的,最主要,一些老开发还是会提及cookie的。总不能不知道人家在说什么吧0.0
关于cookie的domain以及path还有httpOnly这些,因为在这儿重要性不高,也就不多描述了,到时会专门找个时间记录下关于cookie的
res.cookie
res.cookie("access_token", "Bearer 123", { httpOnly: true }).cookie("expire_time", "30000");
效果图如下,备注下,在f12打开的application页面中,点击cookie,然后选择我们的域名以及端口对应的cookie。就可以查看
res.clearCookie
根据键名,清除一个cookie,使用如下
res.clearCookie("expire_time");
效果图,可见已经清除掉了第二个的expire_time了~
关于header
对于header的操作,在网站开发中比较少遇到,更多的是前端在header中传输token给我们,而后台又有在vary等字段的时候设置header的情况,但是堆nodejs而言,比较远(关于vary可以看下mdn的描述),故此,现在假设我们需要在header中添加一个token返回给前端。
res.append
往response的header中添加字段
router.get("/getUserDetail", function (req, res, next) {res.append("token", "12345");res.send();
});
效果图如下
res.locals
res.locals的使用情况比较简单,假设现在我们处理一个外部来的接口,不携带用户信息,只传来一个token,那么我们需要先在中间件中获取到用户的信息(鉴权),接着去根据用户的权限做出不同的操作,而从中间件传递到api的处理的过程,如果为了request的纯净,我们就可以将res中设置一个变量在locals中,而设置在locals中的变量,并不会传递到前端中去,而在node端,却可以安心的使用它。
router.get("/getUserDetail", function (req, res, next) {res.locals.user={name:"mk",sex:1};console.log(res.locals.user.name);res.send();
});
效果图如下
关于json格式的
这是我们最常用的方式,一个api接口,我们需要返回数据,很多时候是json格式的数据,但也因为它的普遍性,所以没有什么需要说明的,只要知道用法就可以了~
res.json
router.get("/getUserDetail", function (req, res, next) {res.json({ fail: false, message: "return by res.json" });
});
res.send
router.get("/getUserDetail", function (req, res, next) {res.send({ fail: false, message: "return by res.send" });
});
两者返回的body没有区别,但是需要注意下content-type,res.send会标注出返回的content-type是application/json.虽然默认都是application/json…
备注下,res.send(“<h1>title</h1>”);也是可以发送html到前端的,只是这样子的话,response中的Content-type就会变成text/html;
关于重定向
重定向,必须是重点,毕竟每次我们登录后,都要跳转到首页,或则是重定向到过来的页面,而这时候就必须要用到重定向了。
res.redirect
router.get("/getUserDetail", function (req, res, next) {res.redirect("/blog/getBlogDetail");//res.redirect是可以跳转到外部的网站
// res.redirect("https://www.baidu.com");
});
res.location
router.get("/getUserDetail", function (req, res, next) {res.location("/blog/getBlogDetail");
});
很遗憾,对于有些同学,想要再重定向之后,将登录的token放在req的header中带过去,但是说过了,req的更多的是只读的(这儿就不贴代码了)
再github上关于这种操作的,比如在redirec中想要更改header的,建议看下这边issues
https://github.com/expressjs/express/issues/3551
但是呢,还是可以有个骚操作,能称得上骚操作,当然只是权宜之计
router.get("/getUserDetail", function (req, res, next) {res.cookie("token","aaaaaaaa");res.redirect("/blog/getBlogDetail");
});
router.get("/getBlogDetail", function (req, res, next) {res.header("content-type", "application/json");console.log(req.cookies["token"]);res.end("博客模块的getBlogDetail");
});
思路就是由于redirect的时候是完结一个请求,从浏览器的角度就是从A接口收到304,然后马上访问b接口,由于是在同一个服务,而根据cookie的特性,就可以将参数设置在A接口的cookie中,从b接口拿到之后,从cookie中删除,但是!cookie本身是http请求的一部分,所以数据量多的时候,会让http请求变得很大,并且可能cookie会被我们的中间件拦截,属于不正规的,有很大风险的方式,所以称之为骚操作
但是现在测试下,而我们需要在server.js中使用cookie-parser来读取cookie。
const cookieParser = require("cookie-parser");
app.use(cookieParser());
关于返回一个html页面
上一篇在路由中,只是简单的设置了一个api,让它能走通,并没有设置到500页面以及404页面,而关于404页面,很多时候需要用到,而为了代码的整洁性,不能将404页面的整个html变成字符串返回过去,所以就需要用到下面的函数(其实渲染的概念不怎么需要解释,想必各位在学习vue,react等都有过渲染的理解,就不多描述了)
个人比较喜欢用pug,就用pug做个简单的例子
server.js中注册pug
app.set("views", path.join(__dirname, "views"));
app.set("view engine", "pug");
在server.js的同级目录创建一个views的文件夹,然后在其中放置一个index.pug的文件,代码如下:
doctype html
html(lang="en")headtitle= pageTitlescript(type='text/javascript').if (foo) bar(1 + 5)bodyh1 Pug - node template engine#container.colif youAreUsingPugp You are amazingelsep Get on it!p.Pug is a terse and simple templating language with astrong focus on performance and powerful features.
在代码中render这个文件
res.render("index", { name: "name" });
即可在浏览器中访问到页面,如何获取参数,pug的官网有一堆资料,我就不在此扩展了,基本动动手指就能找到
需要注意下, render函数是渲染模板引擎,如果是要返回一个html文件,建议用res.sendFile
文件在刚刚描述的views文件夹中创建
router.get("/getUserDetail", function (req, res, next) {res.sendFile(path.join(__dirname, "./../../views/a.html"));
});
关于下载文件
下载文件的绝对不是冷门,也绝对不是最简单的,毕竟文档中关于这些的就有很多,比如刚刚提及到来的sendFile,以及接下来要描述的attachment还有download
res.attachment
Sets the HTTP response Content-Disposition header field to “attachment”. If a filename is given, then it sets the Content-Type based on the extension name via res.type(), and sets the Content-Disposition “filename=” parameter.
router.get("/getUserDetail", function (req, res, next) {res.attachment(path.join(__dirname, "./../../views/a.html"));res.send();
});
没啥好说的,部分同学会忘记res.send。以及需要注意该方式会修改’Content-Disposition’即可~
res.downlaod
res.downlaod绝对是我比较喜欢的下载的方式,很简单,因为有监听函数!!!
router.get("/getUserDetail", function (req, res, next) {res.download(path.join(__dirname, "./../../views/a.html"),(err)=>{console.log(err);console.log("下载完成!");});
});
当然,Content-Disposition也会被修改~,且支持4.16.x以上,但是现在都4.18.x了,我想就不用多说了
参考文档
https://www.expressjs.com.cn/4x/api.html