本文来自作者 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); }, });
扫描下方二维码,阅读完整原文