跨域(二)

作者: 幻城之雪 | 来源:发表于2023-05-15 21:15 被阅读0次

    跨域常用解决方案

    通过jsonp跨域(只接受get请求)

    跨域资源共享(CORS 最常用)(在后端操作)

    nginx代理跨域

    nodejs中间件代理跨域 (react项目中 proxy http-proxy-middleware)

    通过JSONP跨域

    通常为了减轻web服务器的负载,我们把js、css,img等静态资源分离到另一台独立域名的服务器上,在html页面中再通过相应的标签从不同域名下加载静态资源,而被浏览器允许,基于此原理,我们可以通过动态创建script,再请求一个带参网址实现跨域通信
    axios最新版本已经不支持jsonp方法了,不想因为一个jsonp请求就又去引一个依赖,所以决定自己封装一下

    axios.jsonp = (url) => {
    if (!url) {
    console.error('Axios.JSONP 至少需要一个url参数!')
    return;
    }
    return new Promise((resolve, reject) => {
    window.jsonCallBack = (result) => {
    resolve(result)
    }
    var JSONP = document.createElement("script");
    JSONP.type = "text/javascript";
    JSONP.src = `${url}callback=jsonCallBack`;
    document.getElementsByTagName("head")[0].appendChild(JSONP);
    setTimeout(() => {
    document.getElementsByTagName("head")[0].removeChild(JSONP)
    }, 500)
    })
    }
    
    // 第一种 通过jsonp
    axios.jsonp('http://127.0.0.1:3000/user?')
    .then(res=>{
    console.log(res);
    }).catch(err=>{
    console.log(err);
    
    })
    server.js
    const express = require('express');
    const fs = require('fs');
    const app = express();
    // 中间件方法
    // 设置node_modules为静态资源目录
    // 将来在模板中如果使用了src属性 http://localhost:3000/node_modules
    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 Error!');
        }
        res.statusCode = 200;
        res.setHeader('Content-Type','text/html');
        res.end(data);
      })
    })
    // app.set('jsonp callback name', 'cb')
    app.get('/api/user',(req,res)=>{
      console.log(req);
      // http://127.0.0.1:3000/user?cb=jsonCallBack
      // const cb = req.query.cb;
      // cb({})
      // res.end(`${cb}(${JSON.stringify({name:"小马哥"})})`)
      res.jsonp({name:'小马哥'})
    })
    app.listen(3000);
    
    

    jsonp缺点:只能实现get一种请求。

    Nodejs中间件代理跨域

    实现原理:同源策略是浏览器需要遵循的标准,而如果是服务器向服务器请求就无需遵循同源策略。 代理服务器,需要做以下几个步骤:
    接受客户端请求 。
    将请求 转发给服务器。
    拿到服务器 响应 数据。
    将 响应 转发给客户端。index.html文件,通过代理服务器http://127.0.0.1:8080向目标服务器http://localhost:3000/user请求数据

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

    proxyServer.js代理服务器

    const express = require('express');
    const { createProxyMiddleware } = require('http-proxy-middleware');
    const app = express();
    
    

    // 代理服务器操作
    //设置允许跨域访问该服务.

    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();
    });
    
    

    // http-proxy-middleware
    // 中间件 每个请求来之后 都会转发到 http://localhost:3001 后端服务器

    app.use('/', createProxyMiddleware({ target: 'http://localhost:3001', changeOrigin: true }));
    app.listen(8080);
    
    

    业务服务器server.js

    const express = require('express');
    const fs = require('fs');
    const app = express();
    
    

    // 中间件方法
    // 设置node_modules为静态资源目录
    // 将来在模板中如果使用了src属性 http://localhost:3000/node_modules

    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 Error!');
    }
    res.statusCode = 200;
    res.setHeader('Content-Type','text/html');
    res.end(data);
    })
    })
    // app.set('jsonp callback name', 'cb')
    
    app.get('/user',(req,res)=>{
    res.json({name:'小马哥'})
    })
    app.listen(3001);
    
    

    通过CORS跨域

    //设置允许跨域访问该服务.

    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();
    });
    
    

    具体实现:
    响应简单请求:动词为get/post/head,如果没有自定义请求头,Content-Type是application/x-www-form-urlencoded,multipar/form-data或text/plagin之一,通过添加以下解决

     res.header('Access-Control-Allow-Origin', '*');
    
    

    响应prefight请求,需要响应浏览器发出的options请求(预检请求),并根据情况设置响应头

    //设置允许跨域访问该服务.
    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', 'GET,POST,PUT');
    //允许携带cookie
    res.header('Access-Control-Allow-Credentials', 'true');
    res.header('Content-Type', 'application/json;charset=utf-8');
    next();
    });
    
    

    前端
    在这里给大家补充了axios相关用法,具体的看视频

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    </head>
    
    <body>
    <script src='/axios/dist/axios.js'></script>
    <script src="https://cdn.bootcss.com/qs/6.9.1/qs.js"></script>
    <h2>CORS跨域</h2>
    <script>
    axios.defaults.baseURL = 'http://127.0.0.1:3002';
    axios.defaults.headers.common['Authorization'] = 'xaxadadadadad';
    axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
    
    axios.interceptors.request.use(function (config) {
    let data = config.data;
    data = Qs.stringify(data);
    config.data = data;
    // 在发送请求之前做些什么
    return config;
    }, function (error) {
    // 对请求错误做些什么
    return Promise.reject(error);
    });
    axios.post('/login', {
    username: 'xiaomage',
    password: 123
    }, {
    // headers: {
    // 'Authorization': 'adjahdj1313131'
    // },
    // 表示跨域请求时需要使用凭证 允许携带cookies
    withCredentials: true
    })
    .then(res => {
    console.log(res);
    }).catch(err => {
    console.log(err);
    
    })
    </script>
    
    </body>
    
    </html>
    
    

    使用第三方插件cors

    
    npm i cors -S
    const cors = require('cors');
    //简单使用
    app.use(cors())
    配置选项参考链接
    ex:
    app.use(cors({
    origin:'http://localhost:3002', //设置原始地址
    credentials:true, //允许携带cookie
    methods:['GET','POST'], //跨域允许的请求方式
    allowedHeaders:'Content-Type,Authorization' //允许请求头的携带信息
    }))
    
    

    nginx反向代理

    实现原理类似于Node中间件代理,需要你搭建一个中转nginx服务器,用于转发请求。
    使用nginx反向代理实现跨域,是最简单的跨域方式。只需要修改nginx的配置即可解决跨域问题,支持所有浏览器,支持session,不需要修改任何代码,并且不会影响服务器性能。
    实现思路:通过nginx配置一个代理服务器(域名与domain1相同,端口不同)做跳板机,反向代理访问domain2接口,并且可以顺便修改cookie中domain信息,方便当前域cookie写入,实现跨域登录。

    // proxy服务器
    server {
    listen 81;
    server_name www.baidu.com;
    location / {
    proxy_pass http://www.bbbb.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.bbbb.com; #当前端只跨域不带cookie时,可为*
    add_header Access-Control-Allow-Credentials true;
    }
    }
     
    

    相关文章

      网友评论

        本文标题:跨域(二)

        本文链接:https://www.haomeiwen.com/subject/yllvsdtx.html