参考:
https://segmentfault.com/a/1190000009251290?utm_source=tuicool&utm_medium=referral
xhr = new XMLHttpRequest();
//XMLHttpRequest {onreadystatechange: null, readyState: 0, timeout: 0, withCredentials: false, upload: XMLHttpRequestUpload…}
xhr.open('GET', 'https://www.baidu.com/', true);
//undefined
xhr.send();
//undefined
//(index):1 XMLHttpRequest cannot load https://www.baidu.com/. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://192.168.170.131' is therefore not allowed access.
果然是有同源策略的。
然后再试试其他的
xhr = new XMLHttpRequest();
xhr.open('GET', '/wp-login.php', true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send();
在浏览器console里输入之后页面没有半点反应。想起可能是没有设置监听器,但是服务器端应该有访问日志。
果然通过查看apache日志/var/log/apache2/access.log
,发现确实浏览器发出了这个HTTP请求,但是页面完全没有反应。
...
192.168.170.1 - - [01/May/2017:20:01:48 +0800] "GET /wp-login.php HTTP/1.1" 200 1602 "http://192.168.170.131/?s=%E5%AD%A6%E7%94%9F" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36"
Apache访问日志格式参考:
http://blog.csdn.net/newhappy2008/article/details/7604956
接下来设置一下监听器试试看。完整代码走一遍。
if (xhr){
xhr.open('GET', '/wp-login.php', true); //以GET请求方式向/wp-login.php发出异步请求
// 原生ajax会默认使用Content-Type为'text/plain;charset=UTF-8'的方式发送数据
//xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');//这是POST方法用的
xhr.onreadystatechange = function(){
if (xhr.readyState === 4){ // readyState为4表示响应内容解析完成,可以在客户端调用了。
if (xhr.status === 200){ //这时通过status获取状态码, 若为200则认为此时服务器响应为"成功"
console.log('[*]执行成功');
} else {
console.log('[*]执行出错');
}
}
}
}
当然,我们可以用onload
来代替onreadystatechange
等于4的情况,因为onload
只在状态为4的时候才被调用。代码如下:
xhr.onload = function(){ // 指定onload的监听函数
if (xhr.status === 200){ //status为200表示请求成功
console.log('[*]执行成功');
} else {
console.log('[*]执行出错');
}
}
以上便是原生ajax异步请求数据的常见代码。
jQuery中的ajax
jQuery作为一个使用人数最多的js库,其ajax很好地封装了原生ajax的代码,在兼容性和易用性方面都做了很大的提高,让ajax的调用变得非常简单。
下面是一段简单的jQuery的ajax代码:
$.ajax({
method: 'GET', // 1.9.0版本之前使用'type'
url: '/wp-login.php',
dataType: 'json'
}).done(function() {
console.log('[*] 执行成功');
}).fail(function() {
console.log('[*] 执行出错');
});
与原生ajax不同的是,jQuery中默认的Content-Type
是application/x-www-form-urlencoded;charset=UTF-8
其他js框架如Vue.js, Angular.js, React, Fetch API略。
跨域ajax
介绍了各种各样的ajax API,我们不能避免的一个重要问题就是跨域,这里重点讲解下ajax跨域的处理方式。
处理ajax跨域问题主要有一下4终方式:
1. 利用iframe
2. 利用JSONP
3. 利用代理
4. 利用HTML5提供的XMLHttpRequest Level2
第1种和第2种方式大家应该都非常熟悉,都属于前端的活,这里就不做介绍了,这里主要介绍第3种和第4种方式。
什么是跨域
参考:
http://www.cnblogs.com/rainman/archive/2011/02/20/1959325.html
JavaScript出于安全方面的考虑,不允许跨域调用其他页面的对象。但在安全方面的限制的同时也给注入iframe或者ajax应用上带来了不少麻烦。
( 现代浏览器在安全性和可用性之间选择了一个平衡点。在遵循同源策略的基础上,选择性地为同源策略”开放了后门”。 例如img script style等标签,都允许垮域引用资源。)
参考:http://www.cnblogs.com/alsy/p/5470772.html
简单的举例来说,就是由于JavaScript同源策略的限制,a.com
域名上的js无法操作b.com
或是c.a.com
域名下的对象。特别注意两点:
第一,如果是协议和端口造成的跨域问题,”前台”是无能为力的。(因为协议和端口都是需要前台和后台共同遵守才能通信,如果服务器端将协议设置成http而把端口设置为80,客户端是无法通过https以及xxx端口访问服务器的);
第二,在跨域问题上,域仅仅是通过“URL的首部”来识别的。而不会去尝试判断相同IP地址对应着两个域,或者两个IP是否是同一个域。“URL的首部”指window.location.protocol
+window.location.host
即『协议』+『域名』+『端口』
注:其实把这个问题用『跨站』是不是会比『跨域』更加准确没有歧义呢?因为『跨域』总是会联想到跨域名。
跨域的方法
document.domain
document.domain
是比较常用的跨域的方法。实现最简单但只能用于同一个主域下不同子域之间的跨域请求,比如 foo.com
和 img.foo.com
之间,img1.foo.com
和 img2.foo.com
之间。只要把两个页面的document.domain都指向主域就可以了,比如document.domain='foo.com';
。
如,
<!-- www.a.com上的a.html -->
document.domain = 'a.com';
var ifr = document.createElement('iframe');
ifr.src = 'http://script.a.com/b.html';
ifr.style.display = 'none';
document.body.appendChild(ifr);
ifr.onload = function(){
var doc = ifr.contentDocument || ifr.contentWindow.document;
// 在这里操纵b.html
alert(doc.getElementsByTagName("h1")[0].childNodes[0].nodeValue);
};
<!-- script.a.com上的b.html -->
document.domain = 'a.com';
这种方式适用于{www.kuqin.com, kuqin.com, script.kuqin.com, css.kuqin.com}中的任何页面相互通信。
备注:某一页面的domain默认等于window.location.hostname
。
主域名是不带www的域名,例如a.com,主域名前面带前缀的通常都为二级域名或多级域名,例如www.a.com其实是二级域名。 domain只能设置为主域名,不可以在b.a.com中将domain设置为c.a.com。
问题:
1. 安全性,当一个站点(b.a.com)被攻击后,另一个站点(c.a.com)会引起安全漏洞。
2. 如果一个页面中引入多个iframe,要想能够操作所有iframe,必须都得设置相同domain。
动态创建script
虽然浏览器默认禁止了跨域访问,但并不禁止在页面中引用其他域的js文件,并可以自由执行引入的js文件中的function(包括操作cookie、DOM等等)。根据这一点,可以方便地通过创建script节点的方法来实现完全跨域的通信。
window.name
window.name
还真是一个可以在各个域之间共享的东西啊!
这里的条件是不关闭那个Tab(而不是原文说的不关闭浏览器,因为不同Tab之间是不能传递的)
location.hash
较常用,把传递的数据依附在url上。 例如获取子页面bar.com/b.html的高度及其他数据
postMessage()
HTML5新增方法,现代浏览器及IE8+支持,简单易用高大上。
参考:
JavaScript跨域总结与解决办法
js实现跨域(jsonp, iframe+window.name, iframe+window.domain, iframe+window.postMessage)
说说JSON和JSONP,也许你会豁然开朗,含jQuery用例
JSONP跨域问题的解决方法