跨域解决方案jsonpCORSpostMessagehashWebSocketproxy

61次阅读

共计 3459 个字符,预计需要花费 9 分钟才能阅读完成。

什么是跨域

浏览器会有同源策略,域名,协议,端口只要有一个不同就是跨域.

同源策略只限制浏览器端,跨域请求是可以发去的,但是请求响应 response 被浏览器堵塞了 ,是限制了不同源的读,但不限制不同源的写,服务端没有同源策略这一限制,form 表单可以跨域发送信息也是这个原因。

限制

(1)Cookie、LocalStorage 和 IndexDB 无法读取。

(2)DOM 无法获得。

(3)AJAX 请求不能发送

浏览器某些静态文件加载标签不受同源策略限制:<script>< link>< img><video><audio><iframe>

解决跨域的方法

jsonp

  • 原理:客户端告诉服务一个回调函数的名称,服务器在返回的 scritp 里面调用这个回调函数,同时传进客户端需要的数据,这样返回的代码就在浏览器执行了
  • 优缺点:

    • 常用方法,简单适用,老式浏览器全部支持,服务器改造非常小
    • 只能实现 get 一种请求,不安全 容易遭到 xss 攻击
// 前端页面

  function writeDate(_date){document.write(_date);
}


<script src='http://192.168.0.103:9000/getDate?callback=writeDate'></script>

// 服务端返回一个脚本,在这个脚本里面执行 writeDate 函数:function getDate(response, callback){response.writeHead(200, {"Content-Type": "text/javascript"});
    var data = "2016-2-19";
    response.end(callback + "('" + data + "')");
}

//jQuery
$.ajax({
    url: 'http://192.168.0.103:9000/getDate',
    type: 'get',
    dataType: 'jsonp',  // 请求方式为 jsonp
    jsonpCallback: "handleCallback",    // 自定义回调函数名
    data: {}});

//Vue
this.$http.jsonp('http://192.168.0.103:9000/getDate', {params: {},
    jsonp: 'handleCallback'
}).then((res) => {console.log(res); 
})

CORS 跨域资源共享

跨域资源共享 (CORS) 是一种机制,它使用额外的 HTTP 头来告诉浏览器 让运行在一个 origin (domain) 上的 Web 应用被准许访问来自不同源服务器上的指定的资源。—-MDN(CORS)

cors 将跨域请求分为简单请求和非简单请求

简单请求

(1) 请求方法是以下三种方法之一:HEAD/GET/POST

(2)HTTP 的头信息不超出以下几种字段:Accept/Accept-Language/Content-Language/Last-Event-ID/

​ Content-Type:只限于三个值 application/x-www-form-urlencoded、multipart/form-data、text/plain

实现方法

服务端在 http 响应头中添加 Access-Control-Allow-origin

“*”表示任何源都可以访问,也可以指定可以访问的源

非简单请求 / 需预检的请求

必须首先使用 OPTIONS 方法发起一个预检请求到服务器,返回码是 204,预检测通过才会真正发出请求,这才返回 200。

触发非简单请求的条件

  • 使用了下面任一 HTTP 方法满足非简单请求:put/delete/connect/options/trace/patch
  • 人为设置了对 CORS 安全的首部字段集合之外的其他首部字段

postMessage

window.postMessage(message,targetOrigin) 方法是 html5 新引进的特性 ,不受同源策略限制。

用于解决以下方面的问题:
a.)页面和其打开的新窗口的数据传递
b.)多窗口之间消息传递
c.)页面与嵌套的 iframe 消息传递
d.)上面三个场景的跨域数据传递

目前 IE8+、FireFox、Chrome、Opera 等浏览器都已经支持 window.postMessage 方法。

// postMessage
// 窗口 A(http:A.com) 向跨域的窗口 B(http:B.com) 发送信息
Bwindow.postMessage('data', 'http://B.com');
// 在窗口 B 中监听
Awindow.addEventListener('message', function (event) {console.log(event.origin); // 发送源,接受谁
  console.log(event.source); // Awindow 的引用
  console.log(event.data);
}, false);

安全问题

  • 如果不希望从其他网站接收 message,不要为 message 事件添加任何事件侦听器。
  • 始终使用 origin 和 source 属性验证发件人的身份。
  • 始终指定精确的目标 origin,而不是 *。恶意网站可以在不知情的情况下更改窗口的位置,因此它可以拦截使用 postMessage 发送的数据。

hash

hash 为 url# 后的内容,hash 改变页面不刷新,故而可以实现跨域通信

?后的 search 内容,也叫 query 改变页面刷新,不能做跨域通信

// 利用 hash,场景是当前页面 A 通过 iframe 或 frame 嵌入了跨域的页面 B
// 在 A 中伪代码如下:var B = document.getElementsByTagName('iframe');
B.src = B.src + '#' + 'data';
// 在 B 中的伪代码如下
window.onhashchange = function () {var data = window.location.hash;};

WebSocket

http://www.ruanyifeng.com/blo…

HTTP 协议有一个缺陷:通信只能由客户端发起, 做不到服务器主动向客户端推送信息。如果服务器有连续的状态变化,客户端要获知就非常麻烦。我们只能使用 ” 轮询 ”:每隔一段时候,就发出一个询问,了解服务器有没有新的信息。最典型的场景就是聊天室。

WebSocket 最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息

var ws = new WebSocket('wss://echo.websocket.org');
// 发送
ws.onopen = function (evt) {console.log('Connection open ...');
  ws.send('Hello WebSockets!');
};
// 接受
ws.onmessage = function (evt) {console.log('Received Message:', evt.data);
  ws.close();};
// 关闭
ws.onclose = function (evt) {console.log('Connection closed.');
};

vue-cli 3.0 本地环境 proxy 代理跨域

https://cli.vuejs.org/zh/conf…

如果你的前端应用和后端 API 服务器没有运行在同一个主机上,你需要在开发环境下将 API 请求代理到 API 服务器。这个问题可以通过 vue.config.js 中的 devServer.proxy 选项来配置。

devServer.proxy 可以是一个指向开发环境 API 服务器的字符串:

module.exports = {
  devServer: {proxy: 'http://localhost:4000'}
}

这会告诉开发服务器将任何未知请求 (没有匹配到静态文件的请求) 代理到 http://localhost:4000

如果你想要更多的代理控制行为,也可以使用一个 path: options 成对的对象。完整的选项可以查阅 http-proxy-middleware。

module.exports = {
  devServer: {
    proxy: {
      '/api': {
        target: '<url>',
        ws: true,
        changeOrigin: true
      },
      '/foo': {target: '<other_url>'}
    }
  }
}

参考:

不要再问我跨域的问题了

MDN(CORS)

MDN(postMessage)

前端常见跨域解决方案(全)

正文完
 0