前端跨域问题我想很多同学遇到过,或者是刚刚请求数据成功, 然而转眼之后就会报错
XMLHttpRequest cannot load http://www.server.com/server.... No 'Access-Control-Allow-Origin' header is present on the requested resource.Origin 'http://www.client.com' is therefore not allowed access.
我不知道大家有没有遇到过反正我是遇到过,不管在什么时候你都有可能遇到跨域
跨域是什么?
跨域是指一个域下的文档或脚本试图去请求另一个域下的资源,这里跨域是广义的。 其实我们通常所说的跨域是狭义的,是由浏览器同源策略限制的一类请求场景。
为什么会产生跨域?
产生跨域的主要原因是因为同源策略,什么是同源策略呢?我们来看下面的解释
同源策略/SOP(Same origin policy)是一种约定,由Netscape公司1995年引入浏览器,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击。所谓同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个ip地址,也非同源,看看下面的产生跨域的场景你就会明白同源策略的含义。
那么有的人会问了,同源策略会产生跨域为什么还要存在呢?平常我们访问网站的时候都是一个地址对应相同的内容,如果同源策略不存在网站的dom很有可能被钓鱼网站复制,那样你就会上当。
那有的人又问了有了同源策略就安全吗?不是有了它就安全是因为同源策略是基础的安全机制,面对强大的攻击还是需要强大的攻防的
跨域场景
url | 说明 | 是否可以通信 |
---|---|---|
http://www.kuayu.com/img.jpg | 同一域名,不同文件,不同路径 | 可以 |
http://www.kuayu.com/img2.jpg | 同一域名,不同文件,不同路径 | 可以 |
url | 说明 | 是否可以通信 |
http://www.kuayu.com:6666/img.jpg | 同一域名,不同端口 | 不可以 |
http://www.kuayu.com/img2.jpg | 同一域名,不同端口 | 不可以 |
url | 说明 | 是否可以通信 |
https://www.kuayu.com/img.jpg | 同一域名,不同协议 | 不可以 |
url | 说明 | 是否可以通信 |
http://www.kuayu.com/img.jpg | 主域相同,子域不同 | 不可以 |
http://kuayu11.com/img2.jpg | 主域相同,子域不同 | 不可以 |
跨域的解决办法
-
jsonp
Jsonp(JSON with Padding) 是 json 的一种"使用模式",可以让网页从别的域名(网站)那获取资料,即跨域读取数据。
为什么我们从不同的域(网站)访问数据需要一个特殊的技术(JSONP )呢?这是因为同源策略。
同源策略,它是由Netscape提出的一个著名的安全策略,现在所有支持JavaScript
的浏览器都会使用这个策略。同源策略上面咱们已经简单的价绍过了,详细请看上面首先我们先设置script标签,一个简单的jsonp实现,其实就是拼接url,然后将动态添加一个script元素到头部,我来看下面菜鸟教程给与的客户端例子
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>JSONP 实例</title> </head> <body> <div id="divCustomers"></div> <script type="text/javascript"> // 创建函数 function callbackFunction(result, methodName) { // 声明ul标签 var html = '<ul>'; // 循环创建li 插入ul for(var i = 0; i < result.length; i++) { html += '<li>' + result[i] + '</li>'; } html += '</ul>'; // 写入html document.getElementById('divCustomers').innerHTML = html; } </script> // 使用函数 <script type="text/javascript" src="http://www.runoob.com/try/ajax/jsonp.php?jsoncallback=callbackFunction"></script> </body> </html>
我们再来封装一下简单的jsonp函数完整的代码如下面
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>JSONP 实例</title> </head> <body> <div id="divCustomers"></div> <script type="text/javascript"> function jsonp(req){ // 创建script的标签 var script = document.createElement('script'); // 拼接 url var url = req.url + '?callback=' + req.callback.name; // 赋值url script.src = url; // 放入头部 document.getElementsByTagName('head')[0].appendChild(script); } </script> </body> </html> 上面的代码使用方式和咱们菜鸟教程生成的方式是一样的
后台解决跨域
一般有两种解决方法 1.后台返回的数据格式改成jsonp的形式 2.后台response添加header,response.setHeader("Access-Control-Allow-Origin", "*"); "Access-Control-Allow-Origin", "*" 表示所有网站都可以访问 或者可以指定某个具体域名访问response.setHeader("Access-Control-Allow-Origin", "url")
我们来看看后台代码node + koa 的实现,我们可以通过设置header的Access-Control-Allow-Origin
就像是我们设置的token,设置的json格式或是其它格式啊,当然下面的代码是通过使用koa-cors插件进行的解决跨域问题。
var koa = require('koa');
var route = require('koa-route');
var cors = require('koa-cors');
var app = koa();
app.use(cors());
app.use(route.get('/', function() {
this.body = { msg: 'Hello World!' };
}));
app.listen(3000)
其实这一切都归根揭底为cors,那么它是什么呢?它为什么可以解决跨域的问题呢?那我们具体来看看它到底是什么
cros:跨域资源共享 浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple
request),咱们在这里只说一下简单的请求方式:
请求方法是以下三种方法之一:
HEAD
GET
POST
HTTP的头信息不超出以下几种字段:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
Access-Control-Allow-Origin
该字段是必须的。它的值要么是请求时Origin字段的值,要么是一个*,表示接受任意域名的请求。
Access-Control-Allow-Credentials
值是一个布尔值,表示是否允许发送Cookie。默认情况下,Cookie不包括在CORS请求之中。设为true,即表示服务器明确许可,Cookie可以包含在请求中,一起发给服务器。这个值也只能设为true,如果服务器不要浏览器发送Cookie,删除该字段即可
vue解决跨域方案
我们可以在vue-cli配置文件里面设置一个代理,跨域的方法有很多,通常需要后台来进行配置。
我们可以直接通过node.js代理服务器来实现跨域请求。
接下来我们可以通过vue项目中config文件夹下的index.js配置文件
dev: {
// Paths
assetsSubDirectory: 'static',
assetsPublicPath: '/',
proxyTable: {},
// Various Dev Server settings
host: '0.0.0.0', // can be overwritten by process.env.HOST
port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
autoOpenBrowser: false,
errorOverlay: true,
notifyOnErrors: true,
poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
.......
...
}
上面是我从vue项目中拿出来的代码供大家便于寻找,接下来我们需要新建一个js文件,名为proxy.js配置代码如下:
module.exports = {
proxy: {
'/api': { //将www.qj.com映射/apiUrl
target: 'https://www.qj.com', // 接口域名
secure: false, // 如果是https接口,需要配置这个参数
changeOrigin: true, //是否跨域
pathRewrite: {
'^/api': '' //路径重写
}
}
}
}
这把我们需要把proxy.js引入到config文件夹下的index.js中,var proxy = require('./proxy.js')
, 然后将proxyTable: proxy.proxy
插入到我们的dev对象中进行跨域的使用,我们这时候如果设置完了,跨域还是没有解决怎么办,有时候还得需要更改咱们本地的hosts文件以达到我们解决跨域的目的
总结
其实在我开发的经历中遇到跨域的事情还是较少的,一般遇到跨域的时候,基本上都是又后台来处理,以前也会遇到但是使用jsonp的时候还是比较少的,以及上面我们提到的vue-cli的设置解决跨域的问题,我们看到是直接设置webpack的方式来解决,由于vue开发比较多,所以还是比较关注vue的解决方法,有的时候还碰到过比如我们开发web页面和小程序,在小程序请求都没有went,但是到web也会造成跨域问题,所以我们只需设置前台解决跨域问题就行,或者更安全的方式直接让后台一次性解决也免得不小心手机端也跨域了呢。
当然还有很多跨域的解决办法,但是本人遇到与解决的只有这记住方法
参考资料
正确面对跨域,别慌
菜鸟教程
jsonp跨域请求详解——从繁至简
阮一峰cros
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。