结合Nodejs学习跨域问题

下面我以简单的两台node服务器来说明如何使用nginx进行前端跨域访问。

  1. node1服务器 在localhost:8083上启动
const app = express();
app.get('/web/users',(req, res)=>{
    res.json([{name:"张三",age:12},{name:"李四",age:14}]);
    res.end()
})
app.listen(process.env.PORT || 8083);

同域下的前端代码只需调用

function getUsers() {
        var xhr=new XMLHttpRequest();
        xhr.open('GET', 'http://localhost:8083/web/users');
        xhr.send(null);
        xhr.onreadystatechange = function () {
            if (xhr.readyState == 4 && xhr.status == 200) {
              alert(xhr.responseText);
            }else {
              alert(xhr.statusText);
            }
        }
}

这里有一点需要关注的是,前后端代码处在同一个域下,xhr.open() url路径写成下面这样也是可以的,它会默认请求到http://localhost:8083/web/users

xhr.open('GET', '/web/users');

下面我们将node1服务器中的web/users接口删除:

const app = express();
app.listen(process.env.PORT || 8083);

前端此时自然无法访问后台的web/users了,将报一个404错误。

下面增加一个node2服务器,在localhost:8085上启动,同时我们将原先在8083上删除的web/users接口搬迁到8085上:

const app = express();
app.get('/web/users',(req, res)=>{
    res.json([{name:"张三",age:12},{name:"李四",age:14}]);
    res.end()
})
app.listen(process.env.PORT || 8085);

由于8085实现了这个接口,我们尝试在原先8083端口下的ajax调用它试试:

 xhr.open('GET', 'http://localhost:8085/web/users');

如我们所料,浏览器阻止了此次行为,并抛出一个跨域错误。


image

难道就无法访问那个接口了吗?其实服务器之间和服务器之间是可以相互调用的,阻止跨域访问只是在浏览器端做的限制而已。

下面我通过两种方式来实现如何访问到8085上的web/users接口。

1 . node直接作为代理访问

原理就是交由8083后端去访问8085端口接口,访问完成交给前端
8083node后端实现代码:

npm install request --save // 需要安装一个http request模块
const app = express()
const request = require('request')
// 访问此接口时通过request模块去访问8085 再返回给前端。
app.get('/web/users',(req, res)=>{
    var url='http://localhost:8085'+req.url
    console.log(url) // http://localhost:8085/web/users
    req.pipe(request(url)).pipe(res);
})

2. jsonp方式访问

就是通过script 的src,向服务器请求数据,且这不受同源策略限制;然后服务器将相应的数据放入指定的函数回调名中,返回给前端。说的有点绕,下面通过实例讲解:
8083前端请求8085,这里已经不再是ajax请求了,而是直接加载8085上资源。

 
    

上述代码第一个script标签定义了一个函数getUsers 但是并没有执行,只是定义了而已,要想有执行能力,需要

getUsers(data) 

所以我们要让第二个标签script src="http://localhost:8085/jsonp?callback=getUsers" 返回getUsers(data)内容即可,这样第一个标签内定义的函数就可以执行了。返回接口内容只需要放到函数参数里即可
后台8085实现:

const app = express();
const querystring=require('querystring')
const url=require('url')

// 处理前端jsonp请求
app.get('/jsonp',(req,res)=>{
  var qs = querystring.parse(req.url.split('?')[1]); //{callback:'getUsers'}
  var users=JSON.stringify([{name:"张三",age:12},{name:"李四",age:14}]) // 注意需要传成字符串格式
  var callback=`${qs.callback}(${users})`
  res.end(callback)
})

前端返回


image

是不是有点黑魔法的味道!但是缺点也是明显的,首先通过此方式有一定安全性的,通过callback后加一些乱七八糟的东西可能会有xss攻击,最主要的是jsonp不支持post方法。

3 .nginx反向代理器

此方式即类似于第一种node代理方式,也是通过服务器和服务器之间通信,只是不需要8083下后台服务器自己去访问8085,而是专门交给nginx,为什么?姑且认为nginx更加专业吧!
nginx配置

server {
        listen 8007;          # nginx启动端口,需要访问这个端口才能够代理
        server_name localhost:8083; # 需要代理的服务器
        location / {          # 如果你访问127.0.0.1/8002/的话nginx去请求
          proxy_pass http://localhost:8083;
        }
        location /web { #访问/web/aa时会映射成http://localhost:8085/web/aa;
          proxy_pass   http://localhost:8085;
        }
    }

8083请求路径

xhr.open('GET', '/web/users');
image

3 CORS

CORS全称是跨域资源共享 是一个W3C标准,它规定浏览器允许发送ajax到不同域下的服务器来获取数据,从而克服了原来限制,使用CORS需要前后端都支持,现代浏览器基本上都支持。具体CORS的知识可以参考阮一峰博客 http://www.ruanyifeng.com/blog/2016/04/cors.html。node实现只需要增加代码

app.use('*',function (req, res, next) {
  res.header('Access-Control-Allow-Origin', '*'); //这个表示任意域名都可以访问,这样写不能携带cookie了。
//res.header('Access-Control-Allow-Origin', 'http://www.baidu.com'); //这样写,只有www.baidu.com 可以访问。
  res.header('Access-Control-Allow-Headers', 'Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild');
  res.header('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE, OPTIONS');//设置方法
  if (req.method == 'OPTIONS') {
    res.send(200); 
  }
  else {
    next();
  }
});

或者使用现成的CORS模块

npm install cors
var express = require('express')
var cors = require('cors')
var app = express()

var corsOptions = {
  origin: 'http://www.baidu.com',
  optionsSuccessStatus: 200 
}

app.get('/products/:id', cors(corsOptions), function (req, res, next) {
  res.json({msg: '只有百度可以访问'})
})

app.listen(80, function () {
  console.log('CORS-enabled web server listening on port 80')
})

如有不正确,请指正_

你可能感兴趣的:(结合Nodejs学习跨域问题)