最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 跨域的四种(胎教)方式

    正文概述 掘金(缺钱从零开始学前端)   2021-01-03   424

    本文不涉及跨域等基础理论知识(可自行查找何为跨域)

    一:Jsonp跨域(只限于get)

    0.工作前准备

    0.1 npm init --yes

    0.2 cnpm i express -S (express框架)

    0.3 cnpm i axios -S (axios模块)

    1. 正常创建一个js文件和网页

    const express = require('express');
    const app = express();
    const fs = require('fs');
    
    app.get('/',(req,res) => {
      fs.readFile('./index.html', (err,data) =>{
        if (err) {
          res.statusCode = 500;
          res.end('500 Interval Serval');
        }else{
          res.statusCode = 200;
          res.setHeader('Content-Type', 'text/html');
          res.end(data);
        }
      })
    })
    app.listen('3000');
    

    index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
    </head>
    <body>
      <h2>jsonp跨域解决方案</h2>
    </body>
    </html>
    

    2. 在index.html发起跨域请求(需要axios)

    2.1在index.html中引入axios模块

    <script src="/axios/dist/axios.js"></script>
    

    2.2在js文件中使用中间件方法设置node_modules为静态资源目录(注意不是index.html)

    将来在模板中如果使用了src属性 http://localhost:3000/node_modules

    app.use(express.static('node_modules'))
    

    2.3在index中进行跨域请求

        axios.jsonp('http://127.0.0.1:3000/user')
        .then(res => {
          console.log(res);
        }).catch(err => {
          console.log(err);
        }) 
    
    但要注意的是axios已经不支持jsonp方法 要自己包装

    2.4 包装jsonp

    包装jsonp的几个思路

    • 创建一个script标签 设置对应的type url
    • url后面用?callback=回调函数名(之所以用callback是因为express框架中有个res.jsonp()方法,默认的回调名就是callback,也可以自行设置,官方图示)

    跨域的四种(胎教)方式 参考来源: expressjs.com/zh-cn/4x/ap…

    • 回调函数要挂载到window上,不然后端识别不到
        axios.jsonp = url => {
          return new Promise((resolve, reject) =>{
            window.jsonCallBack = function (result){
              resolve(result);
            }
            // 动态创建script脚本 通过src属性 拼接url地址
            // http://127.0.0.1:3000/user?callback=jsonCallBack
    
            let JSONP = document.createElement('script');
            JSONP.type = 'text/javascript';
            JSONP.src = `${url}?callback=jsonCallBack`;
            document.querySelector('head').appendChild(JSONP);
            setTimeout(() => {
              document.querySelector('head').removeChild(JSONP);
            }, 1000);
          })
        }
    

    2.5后端打印结果

      res.jsonp({name:'qlq'});
    

    或者

      const callback = req.query.callback;
      res.end(`${callback}(${JSON.stringify({name:'qlq'})})`)
    

    完整代码

    html.index

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
    </head>
    <body>
      <script src="/axios/dist/axios.js"></script>
    
      <h2>jsonp跨域解决方案</h2>
    
      <script>
        axios.jsonp = url => {
          return new Promise((resolve, reject) =>{
            window.jsonCallBack = function (result){
              resolve(result);
            }
            // 动态创建script脚本 通过src属性 拼接url地址
            // http://127.0.0.1:3000/user?callback=jsonCallBack
    
            let JSONP = document.createElement('script');
            JSONP.type = 'text/javascript';
            JSONP.src = `${url}?callback=jsonCallBack`;
            document.querySelector('head').appendChild(JSONP);
            setTimeout(() => {
              document.querySelector('head').removeChild(JSONP);
            }, 1000);
          })
        }
    
        axios.jsonp('http://127.0.0.1:3000/user')
        .then(res => {
          console.log(res);
        }).catch(err => {
          console.log(err);
        }) 
    
      </script>
    </body>
    </html>
    

    js文件

    const express = require('express');
    const app = express();
    const fs = require('fs');
    
    //中间件设置静态资源目录
    app.use(express.static('node_modules'))
    app.get('/',(req,res) => {
      fs.readFile('./index.html', (err,data) =>{
        if (err) {
          res.statusCode = 500;
          res.end('500 Interval Serval');
        }else{
          res.statusCode = 200;
          res.setHeader('Content-Type', 'text/html');
          res.end(data);
        }
      })
    })
    app.get('/user', (req, res) => {
      //http://127.0.0.1:3000/user?callback=jsonCallBack
      const callback = req.query.callback;
      res.end(`${callback}(${JSON.stringify({name:'qlq'})})`)
      // res.jsonp({name:'qlq'});
    })
    
    app.listen('3000');
    

    二:NodeJS中间价代理跨域

    0 工作前准备与方法一一样

    1. 创建js文件和index.html

    js文件

    const express = require('express');
    const app = express();
    const fs = require('fs');
    
    app.use(express.static('node_modules'))
    app.get('/', (req, res) => {
      fs.readFile('./index.html', (err, data) => {
        if (err) {
          res.statusCode = 500;
          res.end('500 Interval Serval');
        } else {
          res.statusCode = 200;
          res.setHeader('Content-Type', 'text/html');
          res.end(data);
        }
      })
    })
    
    app.get('/user', (req, res) => {
      res.json({name:'proxy成功跨域'})
    })
    app.listen('3001');
    

    index文件

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
    </head>
    <body>
      <script src="/axios/dist/axios.js"></script>
      <h2>proxy中间件代理跨域解决方案</h2>
      <script>
        axios.get('http://localhost:8080/user')
        .then(res => {
          console.log(res);
        }).catch(err => {
          console.log(err);
        }) 
      </script>
    </body>
    </html>
    

    这里的目标是在http://localhost:8080中能跨域访问http://localhost:3001中的数据

    2.创建一个跨域服务器

    2.1 创建需要监听的端口

    const express = require('express')
    const app = express();
    app.listen(8080);
    

    2.2 设置允许跨域访问该服务器

    app.all('*', function (req,res,next) {
      res.header('Access-Control-Allow-Origin', '*');//第二个参数是白名单
      res.header('Access-Control-Allow-Headers', 'Content-Type');
      res.header('Access-Control-Allow-Methods', '*');
      res.header('Content-Type','application/json;charset=utf-8');
      next();
    });
    

    2.3 终端下载中间件 cnpm i http-proxy-middleware -S 并且使用中间件进行转发

    app.use('触发转发的虚拟目录',createProxyMiddleware( { target:'要转发的地址', changeOrigin: true }));

    //下载插件 http-proxy-middleware
    const { createProxyMiddleware } = require('http-proxy-middleware');
    //中间件 筛子 每个请求来之后 都会转发到target 后端服务器
    app.use('/', createProxyMiddleware({ target: 'http://localhost:3001', changeOrigin: true }));
    
    ps:github上有关于http-proxy-middleware的讲解 github.com/chimurai/ht…

    完整的中间件服务器

    const express = require('express')
    const app = express();
    //下载插件 http-proxy-middleware
    const { createProxyMiddleware } = require('http-proxy-middleware');
    
    //代理服务器的操作
    // 设置允许跨域访问该服务器
    app.all('*', function (req,res,next) {
      res.header('Access-Control-Allow-Origin', '*');//第二个参数是白名单
      res.header('Access-Control-Allow-Headers', 'Content-Type');
      res.header('Access-Control-Allow-Methods', '*');
      res.header('Content-Type','application/json;charset=utf-8');
      next();
    });
    
    //中间件 筛子 每个请求来之后 都会转发到target 后端服务器
    app.use('/', createProxyMiddleware({ target: 'http://localhost:3001', changeOrigin: true }));
    
    app.listen(8080);
    

    三:CORS跨域

    有两种方式使用cors
    首先先写index.html

    <body>
      <script src="/axios/dist/axios.js"></script>
    
      <h2>CORS跨域</h2>
    
      <script>
        axios.defaults.baseURL = 'http://127.0.0.1:3002'
        axios.post('/login',{
          username:'qlq',
          password:123
        },{
          headers:{
            'X-Token':'xxxxx'
          },
          //表示跨域请求时需要使用凭证 允许携带cookies
          withCredentials:true
        })
        .then(res => {
          console.log(res);
        }).catch(err => {
          console.log(err);
        }) 
    
      </script>
    </body>
    

    方法1 直接用app.all配置服务器端

    1.跟上面proxy中间件代理用app.all()基本一样 但是如果要做post传值,比如cookie等 就要多加一条

    res.header('Access-Control-Allow-Credentials', 'true');表示允许携带证书(如果有这条 Access-Control-Allow-Origin的值不能是通配符* 不然会报错)

    2.如果前端要在headers头携带x-token等其他属性 需要在Access-Control-Allow-Headers加上这些属性

    const express = require('express');
    const app = express();
    const fs = require('fs');
    
    //设置允许跨域访问该服务.
    app.all('*', function (req, res, next) {
      /// 允许跨域访问的域名:若有端⼝需写全(协议+域名+端⼝),若没有端⼝末尾不⽤加'/'
      res.header('Access-Control-Allow-Origin', 'http://localhost:3002');
      ////允许令牌通过
    
      res.header('Access-Control-Allow-Headers', 'Content-Type,X-Token');
      res.header('Access-Control-Allow-Methods', '*');
    
      //允许携带cookie
      res.header('Access-Control-Allow-Credentials', 'true');
      res.header('Content-Type', 'application/json;charset=utf-8');
      next();
    });
    app.use(express.static('node_modules'))
    app.get('/', (req, res) => {
      fs.readFile('./index.html', (err, data) => {
        if (err) {
          res.statusCode = 500;
          res.end('500 Interval Serval');
        } else {
          res.statusCode = 200;
          res.setHeader('Content-Type', 'text/html');
          res.end(data);
        }
      })
    })
    
    app.post('/login', (req, res) => {
      res.json({message:'cors成功跨域'})
    })
    app.listen('3002');
    

    方法2.使用cors插件

    1.终端cnpm i cors -S

    2.引入cors模块

    3.app.use(cors({配置文件}))

    ps:如何配置参考 github.com/expressjs/c…
    const cors = require('cors')
    //cors
    //设置cors中间件 允许跨域访问
    app.use(cors({
      "origin": "http://localhost:3002",
      "credentials" :true
    }))
    

    如何获取post请求体中的数据

    这里使用cors里面的index.html作为前端页面

    app.post('/login', (req, res) => {
      console.log(req.body);
    })
    

    此时获取的打印出来的结果是undefined 参考文献: expressjs.com/zh-cn/4x/ap…
    这样是无法获取post请求体中的数据 有两种方式获取

    1.app.use(express.json())

    如果post传来的数据时json格式可以直接读取数据

    app.use(express.json())
    app.post('/login', (req, res) => {
      console.log(req.body);
    })
    

    可以获取跨域的四种(胎教)方式

    2.app.use(express.urlencoded({ extended: true}))

    如果post传来的数据时urlencoded格式才可以获取数据

    2.1在服务器端app.use(express.urlencoded({ extended: true}));

    app.use(express.urlencoded({ extended: true}));
    app.post('/login', (req, res) => {
      console.log(req.body);
    })
    

    2.2 在前端将json格式转化为urlencoded格式

    2.2.1 需要借助qs脚本

      <script src="https://cdn.bootcdn.net/ajax/libs/qs/6.9.4/qs.js"></script>
    

    2.2.2 拦截request请求 axios.interceptors.request.use

    1. 获取config.data(request请求体数据)
    2. Qs.stringify() 将数据格式转化为urlencoded
     axios.interceptors.request.use(function (config) {
          let data = config.data;
          //Qs.stringify(data) 将json数据转化为urlencoded
          config.data = Qs.stringify(data);
          console.log(Qs.stringify(data));
          // 在发送请求之前做些什么
          return config;
        }, function (error) {
          // 对请求错误做些什么
          return Promise.reject(error);
        });
    

    即可获取request请求体的数据

    完整代码index.html

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
    </head>
    
    <body>
      <script src="/axios/dist/axios.js"></script>
      <!-- qs -->
      <script src="https://cdn.bootcdn.net/ajax/libs/qs/6.9.4/qs.js"></script>
      <h2>CORS跨域</h2>
    
      <script>
        axios.defaults.baseURL = 'http://127.0.0.1:3002'
        axios.interceptors.request.use(function (config) {
          let data = config.data;
          //Qs.stringify(data) 将json数据转化为urlencoded
          config.data = Qs.stringify(data);
          console.log(Qs.stringify(data));
          // 在发送请求之前做些什么
          return config;
        }, function (error) {
          // 对请求错误做些什么
          return Promise.reject(error);
        });
    
        axios.post('/login', {
          username: 'qlq',
          password: 123
        }, {
          headers: {
            'X-Token': 'xxxxx'
          },
          //表示跨域请求时需要使用凭证 允许携带cookies
          withCredentials: true
        })
          .then(res => {
            console.log(res);
          }).catch(err => {
            console.log(err);
          })
    
      </script>
    </body>
    
    </html>
    

    服务器端js文件

    const express = require('express');
    const app = express();
    const fs = require('fs');
    const cors = require('cors')
    //cors
    //设置cors中间件 允许跨域访问
    app.use(cors({
      "origin": "http://localhost:3002",
      "credentials" :true
    }))
    
    // app.use(express.json()) //json格式
    
    //username=qlq&password=123
    app.use(express.urlencoded({ extended: true})) //urlencoded格式 
    
    // //设置允许跨域访问该服务.
    // app.all('*', function (req, res, next) {
    //   /// 允许跨域访问的域名:若有端⼝需写全(协议+域名+端⼝),若没有端⼝末尾不⽤加'/'
    //   res.header('Access-Control-Allow-Origin', 'http://localhost:3002');
    //   ////允许令牌通过
    
    //   res.header('Access-Control-Allow-Headers', 'Content-Type,X-Token');
    //   res.header('Access-Control-Allow-Methods', '*');
    
    //   //允许携带cookie
    //   res.header('Access-Control-Allow-Credentials', 'true');
    //   res.header('Content-Type', 'application/json;charset=utf-8');
    //   next();
    // });
    app.use(express.static('node_modules'))
    app.get('/', (req, res) => {
      fs.readFile('./index.html', (err, data) => {
        if (err) {
          res.statusCode = 500;
          res.end('500 Interval Serval');
        } else {
          res.statusCode = 200;
          res.setHeader('Content-Type', 'text/html');
          res.end(data);
        }
      })
    })
    
    app.post('/login', (req, res) => {
      //如何获取post请求体中的数据
      console.log(req.body);
      res.json({message:'cors成功跨域'})
    })
    app.listen('3002');
    

    四:nginx反向代理

    实现原理类似于Node中间件处理,需要搭建一个中转nginx服务器,用于转发请求。

    // proxy服务器
    server {
      listen 81;
      server_name www.domain1.com;
      location / {
        proxy_pass http://www.domain2.com:8080; //#反向代理
        proxy_cookie_domain www.domain2.com www.domain1.com; //#修改cookie⾥域名
        index index.html index.htm;
        // 当⽤webpack-dev-server等中间件代理接⼝访问nignx时,此时⽆浏览器参与,故没有同源限制,下⾯的跨域配置可不启⽤
        add_header Access-Control-Allow-Origin http://www.domain1.com;//当前端只跨域不带cookie时,可为*
        add_header Access-Control-Allow-Credentials true;
      }
    }
    

    起源地下载网 » 跨域的四种(胎教)方式

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元