前端跨域问题各种解决方案

时间:2024-04-09 16:36:05

前端跨域问题各种解决方案

本文来自作者 npc光明  GitChat 上分享 「前端跨域问题各种解决方案」,阅读原文查看交流实录。

文末高能

编辑 | 哈比

什么是跨域

(Domain)是网络中独立运行的单位,域之间相互访问则需要建立信任关系(即 Trust Relation)。信任关系是连接在域与域之间的桥梁。

当一个域与其他域建立了信任关系后,2 个域之间不但可以按需要相互进行管理,还可以跨网分配资源,使不同的域之间实现网络资源的共享与管理。

跨域访问是指,没有建立信任关系的两个域之间通讯,但是由于安全原因,跨域访问是被各大浏览器所默认禁止的。

哪些属于跨域

浏览器遵循同源次略,非同源即为跨域,非同源分为三种。

  • host 不一致;

  • 端口不一致;

  • 协议不一致。

上面三种,任意满足一种都是跨域,在请求的时候就会报错。

根据上面的原理,我们可以发现在开发中,我们在浏览器打开的我们本地页面地址和请求地址不在一个源中,所以产生了跨域。

解决跨域的方法和原理

我们知道了跨域的原理,那么开发中,应该如何解决这个问题呢?

反向代理

前面我们了解了,跨域问题的产生是因为浏览器的同源政策造成的,但是服务器与服务器之间的数据交换是没有这个限制。

反向代理就是采用这种方式,建立一个虚拟的代理服务器来接收 internet 上的链接请求,然后转发给内部网络上的服务器,并将从服务器上得到的结果,返回给 internet 上请求链接的客户端。

比如,我们常用的 gulp、grunt、webpack 这些脚手架都是通过这种原理解决的跨域。

具体实现:

1. 使用 gulp 脚手架解决跨域

gulp 中有两个解决跨域的包有 gulp-connect-proxy、http-proxy-middleware,拿 http-proxy-middleware 为例,需要与 gulp-connect 一起使用:


var gulp = require('gulp');                var proxy = require('http-proxy-middleware');            var connect = require('gulp-connect');            gulp.task('server', function() {                connect.server({                     root: 'app',                     livereload: true,                     host: 'localhost',                     port: "8080",                     middleware: function(req, res, next) {                       return [                                 proxy('/', {                                 target: 'targeturl',                                 changeOrigin: true                                    })                                ];                            }                        });                    });        gulp.task('default', ['server'], function() {                    });

2. 使用 grunt 脚手架解决跨域

grunt 和 gulp 其实是类似的,都是需要先连接本地服务,然后设置代理,grunt 使用的的跨域插件是 grunt-connect-proxy,需要与 grunt-contrib-connect 一起使用:


connect: {        options: {                   port: ‘8080‘,                   hostname: ‘localhost‘,                   protocol: ‘http‘,                   open: true,                   base: {                   path: ‘./‘,                    options: {                    index: ‘html/index.html‘                            }                        },                        livereload: true                    },                    proxies: [                        {                            context: ‘/‘ + API_NAME,                            host: ‘localhost‘,                            port: ‘8080‘,                            https: false,                            changeOrigin: true,                            rewrite: proxyRewrite                        }                    ],                    default: {},                    proxy: {                        options: {                            middleware: function (connect, options) {                            if (!Array.isArray(options.base)) {                                    options.base = [options.base];                                }                // Setup the proxy                var middlewares = [require(‘grunt-connect-proxy/lib/utils‘).proxyRequest];                // Serve static files.                options.base.forEach(function (base) {                    middlewares.push(serveStatic(base.path, base.options));                });                // Make directory browse-able.                /*var directory = options.directory || options.base[options.base.length - 1];                 middlewares.push(connect.directory(directory));                 */                return middlewares;             }           }         }        }

3. 使用 grunt 脚手架解决跨域

webpack 如今在前端的三大框架中使用的比较广泛,我们以 vue 为例子,vue-cli 中 config/index.js 中是这样配置代理的:


port: 8090,        proxyTable: {                    '/': {                     target: targeturl,                     changeOrigin: true,                     pathRewrite: {                          '^/': '/'                          },                       }             }

我们可以看到,这三种方式都是需要本地先开启服务的,target 配置请求服务器的地址,    Rewrite 配置代理规则,    changeOrigin 设为 true 意思是同意将主机头的来源更改为目标 URL。

这种代理解决跨域,前端正常写 ajax 就行。

Jsonp

Jsonp 是通过 web 页面所有拥有 src 属性的标签都拥有跨域能力的属性,使客户端通过像调用脚本一样的方式,调用跨域服务器生成的 js 格式文件来获取数据。

具体实现如下。

服务端代码:


router.get('/jsonp', function(req, res, next) {        var userName = req.query.uname;        var password = req.query.pwd;        var data = {            code: 200,            user: userName,            password: password        }        res.jsonp(data);        });

前端端代码:


$.ajax({        async: true,        url: "http://localhost:3000/jsonp",        type: "GET",        dataType: "jsonp", // 返回的数据类型,设置为 JSONP 方式        jsonp: 'callback', // 指定一个查询参数名称来覆盖默认的 jsonp 回调参数名 callback        jsonpCallback: 'xxx', // 设置回调函数名        data: {            "uname": 'jsonp',            "pwd": "456"        },        success: function(response, status, xhr) {            console.log(response);        },        });

扫描下方二维码,阅读完整原文

前端跨域问题各种解决方案