前后端通信中的“跨域”解决方案

305 阅读2分钟

跨域解决方案

协议、域名、端口号,只要有一个不一样都是跨域请求
1、跨域存在的原因
+ 服务器分开部署:WEB服务器、数据服务器、图片服务器…(分开部署,有助于服务器资源的合理利用)
+ 本地开发:本地预览项目 调取 测试服务器上的数据
+ 调取第三方平台API接口
2、跨域主要解决方案
只对一下三种做了讲解
+ JSONP
+ CORS
+ Proxy
(1)JSONP
JSONP:利用SCRIPT标签不存在域的限制实现跨域请求
(1)弊端:
    (A)只能是GET请求 
    (B)不安全,只要服务器支持,谁都可以调用)
(2)callback必须是一个全局上下文中的函数(防止不是全局的函数,需要把这个函数放置到全局上)
// 前端代码
function request(url = "", callback) {
  let script;
  // 把传递的回调函数挂载到全局上
  let name = `jsonp${new Date().getTime()}`
  window[name] = (data) => {
    // data 从服务器获取到了结果
    document.body.removeChild(script);
    delete window[name];
    callback && callback(data);
  }
  // 处理URL
  url += `${url.includes('?') ? '&' : '?'}callback=${name}`
  // 发送请求
  script = document.createElement('script')
  script.src = url
  document.body.appendChild(script);
}

request('http://127.0.0.1:8099/list', result => {
  console.log(result);
});

// 服务器代码
let http = require('http')
let fs = require('fs')
let url = require('url')
// 起服务
let server = http.createServer((req, res)=>{
    let { pathname, query } = url.parse(req.url)
    let callback = query.split('=')[1]
    // 请求
    if(pathname == '/list'){
        // 准备返回的数据
        let result = {
            code: 0,
            data: [10, 20]
        };
        let str = `${callback}(${JSON.stringify(result)})`;
        res.end(str);
    }
})
server.listen(8099,()=>{
    console.log('8099接口请求成功')
})
(2)CORS
客户端正常请求,服务端设置可请求的 源
'Access-Control-Allow-Origin':
(1)*:允许所有源
    不安全;
    不能携带资源凭证;
(2)设置单一源
    安全;
    可以携带资源凭证( 只能是单一一个源);
(3)动态设置多个源
    设置一个白名单,客户端请求的源在白名单中,我们把Allow-Origin动态设置为当前这个源
// 前端
get.onclick = function () {
    fetch('http://127.0.0.1:8099/list', {
      credentials: 'include',
    }).then(res => res.text()).then(data => {
      console.log(data)
    })
}

// 后端
let http = require('http')
let fs = require('fs')
let url = require('url')
//白名单
let allowOrigin = [
    'http://127.0.0.1:8099',
    'http://127.0.0.1:5500',
    'http://127.0.0.1:5502'
]
let server = http.createServer((req, res) => {
    // 设置允许源
    // * : 允许所有源(不安全/不能携带资源凭证)
    // 设置单一源(安全/也可以携带资源凭证/只能是单一一个源)
    // 可以动态设置多个源:每一次请求都会走这个中间件,我们首先设置一个白名单,如果当前客户端请求的源在白名单中,我们把Allow-Origin动态设置为当前这个源

    // 前端请求域名
    if (allowOrigin.includes(req.headers.origin)) {
        res.setHeader('Access-Control-Allow-Origin', req.headers.origin)
        res.setHeader('access-control-allow-credentials', true)
    }
    // 后端设置cookie
    res.setHeader('Set-Cookie', ['a=123;SameSite=Secure'])
    let { pathname } = url.parse(req.url)
    
	// 试探请求:在CORS跨域请求中,首先浏览器会自己发送一个试探请求,验证是否可以和服务器跨域通信,服务器返回200,则浏览器继续发送真实的请求
	req.method === 'OPTIONS' ? res.send('CURRENT SERVICES SUPPORT CROSS DOMAIN REQUESTS!') : next();
    
    // 请求
    if (pathname == '/list') {
        // 准备返回的数据
        let result = {
            code: 0,
            data: [10, 20]
        };
        res.end(JSON.stringify(result));
    }
})
server.listen(8099, () => {
    console.log('8099接口请求成功')
})
(3)Proxy
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    mode: 'production',
    entry: './src/main.js',
    output: {
        filename: 'main.[hash].min.js',
        path: path.resolve(__dirname, 'build')
    },
    devServer: {
        port: '3000',
        compress: true,
        open: true,
        hot: true,
        proxy: {
            '/': {
                target: 'http://127.0.0.1:3001',
                changeOrigin: true
            }
        }
    },
    // 配置WEBPACK的插件
    plugins: [
        new HtmlWebpackPlugin({
            template: `./public/index.html`,
            filename: `index.html`
        })
    ]
}