知识点
- 同源策略
- 跨域
- JSONP
- CORS(服务端支持)
- document.domain
- window.name
- window.postMessage方法
- iframe加form
- 代理 Nginx配置
同源策略详情请点击存在必要性:浅谈CSRF攻击javascript
同源策略限制了从同一个源加载的文档或脚本如何与来自另外一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要安全机制。css
跨域,指的是从一个域名去请求另一个域名的资源。即跨域名请求!跨域时,浏览器不能执行其余域名网站的脚本,是由浏览器的同源策略形成的,是浏览器施加的安全限制。html
跨域的严格一点来讲就是只要协议,域名,端口有任何一个的不一样,就被看成是跨域。前端
<img src="跨域的图片地址" />
<link href="跨域的css地址" />
<script src="跨域的js地址"></script>
提示:
咱们有时候就会引入一些cdn 的js和css等,这些地址确定不是同源的,但却可使用。
另外,有些图片若是作了防盗链限制(服务端上的处理)的话,就不能使用。
感兴趣的请点击个人另外一篇博客:图片视频等资源中转,用nodejs解决防盗链问题java
浏览器这样作,都是有必定的考虑的,都是为了有一些功能,好比说:node
<img />
可用于统计打点,可以使用第三方统计服务<link />
<script>
可以使用CDN,CDN通常都是外域<script>
可实现JSONP全部的跨域,都必须通过server端容许和配合
未经server端容许就实现跨域,说明浏览器有漏洞,危险信号web
首先,咱们要先明白
访问 https://www.baidu.com/,服务端必定会返回一个html文件吗?
服务端能够任意动态拼接数据返回,只要符合html格式要求。
同理于: <script src="xxxxxxxx/getData.js">
服务端也许并非返回一个getData.js静态文件,而是服务端经过拼接任何数据返回给你,只要拼接的数据格式不报错就行。ajax
那么,咱们已经知道了json
<script>
可绕过跨域限制<script>
就能够得到跨域的数据,只要服务端愿意返回以上便是JSONP的实现原理,归纳以下:
在HTML
标签里,一些标签好比script
,img
这样的获取资源的标签是没有跨域限制的。
动态插入script
标签,经过script
标签引入一个js
文件,这个js
文件载入成功后会执行咱们在url
参数中指定的函数,而且会把咱们须要的json
数据做为参数传入canvas
优势: 兼容性好,简单易用,支持浏览器与服务器双向通讯。
缺点: 只支持GET请求。
简易代码示例:
后端被请求文件:jsonp.js (由后端处理拼接生成)
// jsonp.js 文件内容 abc( { name: 'xxx' } )
前端请求代码:
<script> window.abc = function (data) { console.log(data) } </script> <script src="http://localhost:8002/jsonp.js?username=xxx&callback=abc"></script>
代码讲解:
前端经过<script>
请求http://localhost:8002/jsonp.js
并传入相应参数?username=xxx&callback=abc
后端收到请求,根据路径和参数等信息,动态处理拼接出jsonp.js
文件返回给前端。
前端根据jsonp.js
文件内容,执行window.abc
函数,输出内部数据。
CORS是一个w3c标准,全称是"跨域资源共享"(Cross-origin resource sharing),当一个请求url的协议,域名,端口三者之间任意与当前页面地址不一样即为跨域.它容许浏览器向跨源服务器发送XMLHttpRequest请求,从而克服AJAX只能同源使用的限制.
原理: 服务器对于CORS
的支持,主要就是经过设置Access-Control-Allow-Origin
来进行的。若是浏览器检测到相应的设置,就能够容许Ajax
进行跨域的访问。
浏览器将CORS请求分为两类:简单请求和非简单请求
只要知足如下两大条件,就属于简单请求:
HEAD
GET
POST
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type
:只限于三个值application/x-www-form-urlencoded
、multipart/form-data
、text/plain
不一样时知足上面两个条件,就是非简单请求
代码简易示例: CORS - 服务器设置 http header
// 第二个参数填写容许跨域的域名称,不建议直接写"*" response.setHeader("Access-Control-Allow-Origin","http://localhost:8080"); response.setHeader("Access-Control-Allow-Headers","X-Requested-With"); response.setHeader("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS"); // 接收跨域的cookie response.setHeader("Access-Control-Allow-Credentials","true");
document.domain
来跨域将子域和主域的document.domain
设为同一个主域。
前提条件:这两个域名必须属于同一个基础域名,并且所用的协议,端口都要一致,不然没法使用document.domain
来进行跨域。
详细信息请看
window
对象有个name属性,该属性有个特征:即在一个窗口(window
)的生命周期内,窗口载入的全部页面都是共享一个window.name
的,每一个页面对window.name都有读写的权限,window.name
是持久存在一个窗口载入过的全部页面中的。
HTML5
中新引进的window.postMessage方法来跨域传送数据window.postMessage()是HTML5的一个接口,专一实现不一样窗口不一样页面的跨域通信。
代码示例发送方:
<template> <div> <button @click="postMessage">给http://crossDomain.com:9099发消息</button> <iframe name="crossDomainIframe" src="http://crossdomain.com:9099"></iframe> </div> </template> <script> export default { mounted () { window.addEventListener('message', (e) => { // 这里必定要对来源作校验 if (e.origin === 'http://crossdomain.com:9099') { // 来自http://crossdomain.com:9099的结果回复 console.log(e.data) } }) }, methods: { // 向http://crossdomain.com:9099发消息 postMessage () { const iframe = window.frames['crossDomainIframe'] iframe.postMessage('我是[http://localhost:9099], 麻烦你查一下你那边有没有id为app的Dom', 'http://crossdomain.com:9099') } } } </script>
代码示例接收方:
<template> <div> 我是http://crossdomain.com:9099 </div> </template> <script> export default { mounted () { window.addEventListener('message', (e) => { // 这里必定要对来源作校验 if (e.origin === 'http://localhost:9099') { // http://localhost:9099发来的信息 console.log(e.data) // e.source能够是回信的对象,其实就是http://localhost:9099窗口对象(window)的引用 // e.origin能够做为targetOrigin e.source.postMessage(`我是[http://crossdomain.com:9099],我知道了兄弟,这就是你想知道的结果:${document.getElementById('app') ? '有id为app的Dom' : '没有id为app的Dom'}`, e.origin); } }) } } </script>
JSONP只能发送GET请求,由于本质上script加载资源就是GET。若是要发送POST请求能够以下
后端代码:
// 处理成功失败返回格式的工具 const {successBody} = require('../utli') class CrossDomain { static async iframePost (ctx) { let postData = ctx.request.body console.log(postData) ctx.body = successBody({postData: postData}, 'success') } } module.exports = CrossDomain
前端代码:
const requestPost = ({url, data}) => { // 首先建立一个用来发送数据的iframe. const iframe = document.createElement('iframe') iframe.name = 'iframePost' iframe.style.display = 'none' document.body.appendChild(iframe) const form = document.createElement('form') const node = document.createElement('input') // 注册iframe的load事件处理程序,若是你须要在响应返回时执行一些操做的话. iframe.addEventListener('load', function () { console.log('post success') }) form.action = url // 在指定的iframe中执行form form.target = iframe.name form.method = 'post' for (let name in data) { node.name = name node.value = data[name].toString() form.appendChild(node.cloneNode()) } // 表单元素须要添加到主文档中. form.style.display = 'none' document.body.appendChild(form) form.submit() // 表单提交后,就能够删除这个表单,不影响下次的数据发送. document.body.removeChild(form) } // 使用方式 requestPost({ url: 'http://localhost:9871/api/iframePost', data: { msg: 'helloIframePost' } })
server{ # 监听9099端口 listen 9099; # 域名是localhost server_name localhost; #凡是localhost:9099/api这个样子的,都转发到真正的服务端地址http://localhost:9871 location ^~ /api { proxy_pass http://localhost:9871; } }
// 请求的时候直接用回前端这边的域名http://localhost:9099,这就不会跨域,而后Nginx监听到凡是localhost:9099/api这个样子的,都转发到真正的服务端地址http://localhost:9871 fetch('http://localhost:9099/api/iframePost', { method: 'POST', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' }, body: JSON.stringify({ msg: 'helloIframePost' }) })
帅气逼人的家伙们,赏个赞呗~ _(¦3」∠)_
前端知识体系 目录结构