Node.js是一个事件驱动I/O服务端JavaScript环境,基于Google的V8引擎,简单的说 Node.js 就是运行在服务端的 JavaScript。
不过本文要讲的解决跨域问题
例如:我们当前服务为http://localhost:8080/,现在我们有一个需求,如果我们请求/api,而这个api请求又和当前服务不是同源的,即涉及到跨域问题,相信很多开发者都有遇到这样的问题。
我之前有一篇博文《浅谈跨域》是讲述一些跨域问题的,其中讲到了在vue-cli项目中在webpack配置一下proxyTable
即可以实现在开发环境下进行跨域请求。
那生产环境依然涉及到跨域怎么办?
node代理服务!,用到的关键依赖是http-proxy-middleware
http-proxy-middleware
http-proxy-middleware是用于把请求代理转发到其他服务器的中间件。
- 原来请求过程:本地服务——x(浏览器同源策略)——> api
- 使用node代理:本地服务——(node代理同意该请求)——> Node代理 ——(脱离浏览器,无同源策略)——> api
node代理服务代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22let proxy = require('http-proxy-middleware')
let express = require('express')
let app = express();
// 跨域配置
app.all('*', function (req, res, next) {
if (!req.get('Origin')) return next()
// 用 "*" 以同意所有请求源请求该服务
res.set('Access-Control-Allow-Origin', '*')
// 用 "*" 以同意所有请求方式 (get/post/patch...)
res.set('Access-Control-Allow-Methods', '*')
// 允许的请求头配置,可根据自己的要求填写更多
res.set('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type')
if (req.method === 'OPTIONS') return res.sendStatus(200)
next()
})
// 转发至目标(这里以http://XXX.xxx/api代替,应写具体)
app.use('/api', proxy({target: 'http://XXX.xxx/api', changeOrigin: true}));
app.listen(3000);
现在,我们利用express在3000端口启动了一个小型的服务器,利用了1
app.use('/api', proxy({target: 'http://XXX.xxx/api', changeOrigin: true}));
这句话,使发到3000端口的/api请求转发到了3001端口。即请求http://localhost:3000/api相当于请求http://XXX.xxx/api
- 本地服务——(node代理同意该请求)——> Node代理 ——(脱离浏览器,无同源策略)——> api
要知道,‘同源,跨域’为浏览器的安全策略,而脱离了浏览器的的node代理服务,已不再受该策略的束缚,实现跨域请求。
HTTPS
有时候我们还需要使node代理服务为HTTP通道,以满足开发需求,要知道,以HTTPS和HTTP之间的请求也是存在问题的。
HTTPS(全称:Hyper Text Transfer Protocol over Secure Socket Layer),是以安全为目标的HTTP通道,简单讲是HTTP的安全版。即HTTP下加入SSL层,HTTPS的安全基础是SSL
要实现从HTTP到HTTPS的改变 最重要的就是SSL证书
SSL证书的获取我就不多讲了,很多平台都有免费的,像阿里云,腾讯云等都可以之间申请免费的SSL证书,当然,您要是有钱大佬,也可以花钱购买。
很多平台拿到的证书文件可能没有直接说明哪些是用于Node服务的,其他都有区分
这里以腾讯云获取的证书为例
我们只需要用Nginx文件下的文件即可,其他平台也是一样获取Nginx服务项的文件
将其放到node服务目录下
则原来的node服务代码修改为1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34let proxy = require('http-proxy-middleware')
let express = require('express')
let https = require("https"); //添加代码
let fs = require("fs"); //添加代码
const httpsOption = { //添加代码
key : fs.readFileSync('./nginx/xxxxxxxxx.key'),
cert: fs.readFileSync('./nginx/xxxxxxxxx.crt')
}
let app = express()
// 跨域配置
app.all('*', function (req, res, next) {
if (!req.get('Origin')) return next()
// 用 "*" 以同意所有请求源请求该服务
res.set('Access-Control-Allow-Origin', '*')
// 用 "*" 以同意所有请求方式 (get/post/patch...)
res.set('Access-Control-Allow-Methods', '*')
// 允许的请求头配置,可根据自己的要求填写更多
res.set('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type')
if (req.method === 'OPTIONS') return res.sendStatus(200)
next()
})
// 转发至目标(这里以http://XXX.xxx/api代替,应写具体)
app.use('/api', proxy({target: 'http://XXX.xxx/api', changeOrigin: true}));
app.listen(3000);
https.createServer(httpsOption, app).listen(444,() => { //添加代码
console.log(`HTTPS Server is running on: 444`)
})
注:为了不占用默认的443端口,选用444端口
这样,我们既可以请求http://localhost:3000/api,也可请求https://localhost:444/api,都是一样转而请求http://XXX.xxx/api