第一部分 跨域及其相关知识
什么是同源策略:指域名、协议、端口均相同,默认端口是80,二级域名也不是同源。
为了保证用户信息的安全,防止恶意的网站窃取数据。
浏览器之间不能访问不同域名的cookie,提交表单的时候不受同源策略的限制,所以有跨站脚本攻击
同源策略的限制对象(跨域)
1)cookie、localStorage、IndexDB无法读取
2)DOM无法获取
3) AJAX请求不能发送
跨域的方法:
1、设置同源策略(hosts)
test.xxx.com a.html
<script>
document.domain = 'example.com'; //设置同源策略
document.cookie = 'text1=hello';
</script>
test2.xxx.com b.html
<script>
可以取到cookie中的值
</script>
后台设置同源 domain = .example.com;
注意这种方法只适用于cookie和iframe窗口,localStorage和IndexDB无法通过这种方式规避同源政策,而要使用PostMessage API。
2、iframe通过下面三种方式实现跨域的信息传递
a)片段识别符,即#号后面的内容,父窗口通过#后面的内容传递给子窗口信息
父窗口代码:
var src = originURL + '#' + data;
document.getElementById('myIFrame').src = src;
子窗口代码:
window.onhashchange = checkMessage;
function checkMessage(){
var messaage = window.location.hash;
}
同样的,子窗口也可以改变父窗口的片段标识符。
如果只改变片段标识符页面不会刷新。
b)window.name
window.name属性的特点无论是否同源,只要在同一个窗口里,前一个网页设置了这个属性后,后一个网页可以读取它。
这个方法感觉没什么用,要不然就是我没有理解,可以参考原文
http://www.ruanyifeng.com/blog/2016/04/same-origin-policy.html
c)window.postMessage
跨文档通信API,这个是window对象新增的方法,允许跨窗口通信,无论两个窗口是否同源。
var popup = window.open('http://bbb.com', 'title');
popup.postMessage('Hello World!','http://bbb.com');
postMessage方法的第一个参数是具体的信息内容,第二个参数是接收信息的窗口的源,即‘协议+域名+端口’,也可设为*,表示不限制域名,向所有窗口发送
event.source:发送消息的窗口
event.origin:消息发向的网址
event.data: 消息内容。data的内容最新的浏览器可以接收任何格式的数据
window.addEventListener('message', receiveMessage);
function receiveMessage(event) {
if (event.origin !== 'http://aaa.com') return;
if (event.data === 'Hello World') {
event.source.postMessage('Hello', event.origin);
} else {
console.log(event.data);
}
}
window.onmessage = function(e){}
写法是上面这种形式,源页面打开其他域的页面,然后用获取的窗口变量postMessage,新打开的页面会收到发送的信息。
参考文档:https://developer.mozilla.org/zh-CN/docs/Web/API/Window/postMessage
postMessage要注意安全性,一定要指明来源和接收的格式。因为监听方法可以收到任何网页的信息
还可以通过postMessage来操作localStorage
加强版的子窗口接收消息的代码如下。
window.onmessage = function(e) { if (e.origin !== 'http://bbb.com') return; var payload = JSON.parse(e.data); switch (payload.method) { case 'set': localStorage.setItem(payload.key, JSON.stringify(payload.data)); break; case 'get': var parent = window.parent; var data = localStorage.getItem(payload.key); parent.postMessage(data, 'http://aaa.com'); break; case 'remove': localStorage.removeItem(payload.key); break; } };
加强版的父窗口发送消息代码如下。
var win = document.getElementsByTagName('iframe')[0].contentWindow; var obj = { name: 'Jack' }; // 存入对象 win.postMessage(JSON.stringify({key: 'storage', method: 'set', data: obj}), 'http://bbb.com'); // 读取对象 win.postMessage(JSON.stringify({key: 'storage', method: "get"}), "*"); window.onmessage = function(e) { if (e.origin != 'http://aaa.com') return; // "Jack" console.log(JSON.parse(e.data).name); };
3、ajax实现跨域(除了可以使用代理服务器,如nginx,proxy)
防护垫
a)jsonp(JSON with Padding)
jsonp的原理是根据script src的跨域特性实现的,需要服务器配合,调用一个callback函数
首先,网页动态插入<script>
元素,由它向跨源网址发出请求。
function addScriptTag(src) { var script = document.createElement('script'); script.setAttribute("type","text/javascript"); script.src = src; document.body.appendChild(script); } window.onload = function () { addScriptTag('http://example.com/ip?callback=foo'); } function foo(data) { console.log('Your public IP address is: ' + data.ip); };
上面代码通过动态添加<script>
元素,向服务器example.com
发出请求。注意,该请求的查询字符串有一个callback
参数,用来指定回调函数的名字,这对于JSONP是必需的。
服务器收到这个请求以后,会将数据放在回调函数的参数位置返回。
foo({ "ip": "8.8.8.8" });
由于<script>
元素请求的脚本,直接作为代码运行。这时,只要浏览器定义了foo
函数,该函数就会立即调用。作为参数的JSON数据被视为JavaScript对象,而不是字符串,因此避免了使用JSON.parse
的步骤。
b)WebSocket
WebSocket是一种通信协议,使用ws://
(非加密)和wss://
(加密)作为协议前缀。该协议不实行同源政策,只要服务器支持,就可以通过它进行跨源通信。发送的头信息中有一个origin,服务器会根据这个源来判断是否是对的客户端。应用场景,数据实时变化的页面,如股票页面,聊天页面等。
参考文档:https://www.cnblogs.com/wei2yi/archive/2011/03/23/1992830.html
c)CORS
CORS是跨源资源分享(Cross-Origin Resource Sharing)的缩写,它是W3C标准,是跨源AJAX请求的根本解决方法。相比JSONP只能发GET
请求,CORS允许任何类型的请求。
它发出的也是XMLHttpRequest请求,它的内部机制是:
CORS需要浏览器和服务器同时支持,目前所有浏览器都支持该功能,IE浏览器不能低于IE10。
整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。
因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
参考资料: http://www.ruanyifeng.com/blog/2016/04/cors.html
以上除了CORS是后台跨域设置,其他都是前端跨域,除此之外还有以下方式
img link(css 的攻击注入,background请求跨域)
把代码压缩进图片(canvas)
小技巧:
可以用img来测试网速,并作一些其他的处理,方式就是用
var img = new img();
img.src = ''; //1kb的图片
var start = Date.now();
img.onload = function(){
var end = Date.now();
var t = end - start;
}
第二部分 html语义化,常用的语义化结构
常用的语义化结构:
<header>
<nav></nav>
</header>
<div class="content">
<section></section>
<section></section>
<aside></aside>
<ul></ul>
<ol></ol>
<p></p>
</div>
<footer></footer>
这个目前用的少,语义化知道,但是基本没用,语义化的作用:
a、去掉或样式丢失的时候能让页面呈现清晰的结构
b、屏幕阅读器(如果访客有视障碍)完全会根据你的标记来“读”你的网页
c、PDA、手机等设备可能无法像普通电脑的浏览器一样来渲染网页(通常是因为这些设备对css的支持较弱)
d、搜索引擎的爬虫也依赖于标记来确定上下文和各个关键字的权重。搜索引擎是很重要的访客。你的页面是否对爬虫容易理解非常重要,因为爬虫很大程度上会忽略用于表现的标记,而只注重语义标记,SEO主要还是靠你网站的内容和外部链接的
e、便于团队开发和维护,代码可读性较好
html少写:减少dom渲染的时间,使用::before ::after,来增加元素