上篇文章讲了vue项目使用服务器代理完成跨域,这次说一个服务端来完成这个跨域工作,就是cors跨域。
CORS背后的基本思想是使用自定义的HTTP头部允许浏览器和服务器相互了解对方,从而决定请求或响应成功与否。
其实这个自从ajax2.0就支持了。这里我们讲下node是怎么来配置这个cors跨域的这里还是以express框架为例,这个相对koa比较好理解点,后面会讲koa。
```javascript
//当你使用的是常规的跨域请求,只要设置,响应头
app.use((req, res) => {
res.header('Access-Control-Allow-Origin','*');//设置跨域需要的响应头。
})
```
复制代码
上面是对所有的请求都同意跨域,当然,如果考虑安全,你也可以根据自己的需要,先对请求做一个验证,再决定是否加这个响应头,比如
```javascript
app.use((req, res, next) => {
if(req.headers['origin'] && url.parse(req.headers['origin']).hostname == 'localhost'){
res.header('Access-Control-Allow-Origin','*');//自定义中间件,设置跨域需要的响应头。
}else{
next()
}
})
```
复制代码
针对普通的跨域请求只要加个响应头即可,如果是特殊的请求,比如put,delete,或者你在请求头里定义了一些自己的东西,这时你就要设置服务端相应的Access-Control-Allow-Methods和Access-Control-Allow-Headers,这个根据自己的情况来加就可以了
是不是一下子感觉cors跨域原来这么简单。
接下来我们讲下文件上传
在express框架里,如果要上传文件需要依赖一个中间件multer,当然也可以是别的中间件,这里以multer为例。 服务端代码
const express = require('express')
const router = express.Router()
const multer = require('multer') //express框架上传文件所需要的中间件
var upload = multer({ //multer中间件的使用方法可以命令行npm search multer
dest: './uploads/' //决定文件上传存放的目录
})
router.post('/upload', upload.single('avatar'), (req, res) => { //注意这里的avatar
var fileName = "";
console.log(req.file);
if (req.file != undefined) {
fileName = new Date().getTime() + "_" + req.file.originalname;
fs.rename(req.file.path, __dirname + "/" + fileName, err => {
if(err) console.log(err)
}); //重命名,加后缀,不然图片会显示乱码,打不开
}
res.send("1");
})
module.exports = router;
复制代码
如果你要上传多个文件可以将上面的upload.single改为upliad.array('文件名', 数量)
客户端代码,这里要注意当你使用formData来append你的文件的时候,一定要保证文件名和服务端要接受的文件名一致。
uploadImg () {
let formData = new FormData();
formData.append('avatar', this.file) //注意,这里必须上传文件的name为avatar要和服务端接收的保持一致
this.$axios.post('/api/admin/upload', formData)
复制代码
路由可以帮助我们极大的优化项目结构
一个大点的项目会有很多请求路径,每个路径下面还会细分,这时路由的作用就体现出来了。 在express中,它本身就带有路由模块,这里我们来简单的演示下
//server.js
const express = require('express')
const bodyParser = require('body-parser')
let app = express()
app.listen(8080)
app.use(bodyParser.urlencoded({
extended: false
}))
app.use('/user', require('./routers/user')) //当收到/user请求时会去找对应的user文件
app.use('/news', require('./routers/news'))
//当收到/user请求时会去找对应的news文件
//user.js,news.js也与其类似
const express = require('express')
const router = express.Router()
module.exports = router
router.get('/login', (req,res) => {})
复制代码
这样一来,我们就把每个请求都分离出去,让server.js看起来很清爽。
讲道理,cookie和session是服务端和客户端通信的重要保障。
因为互联网上的东西彼此之间根本不认识,http就是无状态请求,只能通过类似于暗号一样的东西来确定对方是否可信。而cookie和session就相当于这个暗号。 说下cookie和sesiion到底是什么:
cookie:它存储在客户端,也就是浏览器,但每次向服务端发起请求时都会带上cookie作为用户的凭证。
注意:任何放在客户端的东西都是不安全的,cookie也是,它很容易被篡改,所以一般重要信息都不会放在cookie。而且,它有大小的限制,一般只有4k。当然,为了防篡改,cookie有一个签名机制。
session:存储在服务器,不是独立存在的,一般基于cookie,就是在cookie里会保存一个id用来在服务端做验证,当然也可以用别的第三方验证
因为session是存储在服务端,相对会安全很多,而且理论上没有大小的限制。
接下来讲下怎么在express中使用cookie和session
使用cookie需要中间件cookie-parser,直接cnpm i cookie-parser
const cookieParser=require("cookie-parser");
app.use(cookieParser('secret'));
//注册登陆post 方法;
Router.post("/login",function (req,res) {
const {userid}=req.cookies; //读取浏览器传过来的cookie
res.cookie("userid",'chyingp', {'自己设置参数'}) //设置响应头的cookie
复制代码
可以在响应头里设置: maxAge存活时间,domain域名,path路径, httpOnly是否只让服务端操作, secure是否只用在https 还有一个signed,这个就是是否签名,当为true就要签名。
res.cookie('userid', 'chyingp', {signed: true});
复制代码
这样配合上面的cookieParser就完成一个签名,下面讲下cookieParser是怎么实现这个签名的
res.cookie = (name, value, options) => {
var secret = this.req.secret;
var signed = opts.signed;
// 如果 options.signed 为true,则对cookie进行签名
if (signed) {
val = 's:' + sign(val, secret);
}
this.append('Set-Cookie', cookie.serialize(name, String(val), opts));
return this;
};
复制代码
里面的sign函数实现:
function sign (val, secret) {
return val + '.' + hmac(val, secret); //hmac是一种密钥码
}
复制代码
到这里,我们就实现了一个简单版的cookie-parser中间件,我记得有的面试官会问能不能手写中间件,其实也没什么难的。
最后说下session
express用session需要cookie-session中间件 示例代码:
const cookieSession = require('cookie-session');
app.use(cookieSession({
//会话在cookie中的名称
name: 'session',
//用于签名的密钥
keys: ['j239r5ndgffhfghhgjhyyw45646fte'],
//cookie过期时间,单位毫秒
maxAge: 3600 * 1000
}));
//使用
app.get('/', function (req, res) {
//获取会话数据
console.log(req.session);
//设置会话数据
req.session.name = 'zhangsan';
res.end();
});
复制代码
到这里,其实已经可以使用node进行简单的开发了,有接口,有路由,有文件上传,有cookie,session。起码用来做一个自己的个人博客是ok的。 后面,就不讲express了,在大型项目中,大家其实都更倾向于koa,因为express是基于回调的,容易死于回调。。。最新的koa是基于async await的,用起来更爽,后面我会分享一些koa的使用。