文章结构

  • 手写实现 XMLHttpRequest
    • 状态码说明
      • xhr.readyState中的状态码说明
      • xhr.status中的状态码说明
  • Fetch API
  • 跨域
    • 跨域
    • 解决跨域
      • JSONP
      • 服务器设置 http header

手写实现 XMLHttpRequest

1
2
3
4
5
6
7
8
9
10
11
12
var xhr = new XMLHttpRequest();

xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
console.log(xhr.responseText);
}
}
};

xhr.open('GET', '/api', false);
xhr.send(null);

状态码说明

上述代码中,两处涉及到了状态码。分别是:

  • xhr.readyState是浏览器判断请求过程各个阶段。
  • xhr.status是 http 协议中规定的不同结果的返回状态说明

xhr.readyState中的状态码说明

  • 0 —— 代理被创建,但未调用 open()方法
  • 1 —— open()方法已经被调用
  • 2 —— send()方法已经被调用,并且头部和状态已经可以获得。
  • 3 —— 下载中,并且 responseText 中已经包含部分数据。
  • 4 —— 下载完成

http 协议中规定的不同结果的返回状态说明

xhr.status中的状态码,有 2**,300**,4**,5**这几种。常见的有以下这几种:

  • 200 正常
  • 404 未找到资源
  • 5** 服务器出错了

Fetch API

目前已经有一个获取 HTTP 请求更加方便的 API:Fetch,通过 Fetch 提供的 fetch()这个全局函数方法可以很简单地发起异步请求,并且支持 Promise 的回调

1
2
3
4
5
6
7
8
9
10
fetch('some/api/data.json', {
method: 'POST', // 请求类型 GET、POST
headers: {}, // 请求的头信息,形式为 Headers 对象或 ByteString
body: {}, // 请求发送的数据 blob、BufferSource、FormData、URLSearchParams(get 或head 方法中不能包含 body)
mode: '', // 请求的模式,是否跨域等,如 cors、 no-cors 或 same-origin
credentials: '', // cookie 的跨域策略,如 omit、same-origin 或 include
cache: '', // 请求的 cache 模式: default、no-store、reload、no-cache、 force-cache 或 only-if-cached
}).then(function(response) {
...
});

跨域

跨域

浏览器有同源策略,即一个域下的页面,无法通过 Ajax 请求获取到其他域的接口。

在 url 中,只要协议、域名、端口不同都算做跨域。

但是在 HTML 中有三个标签能逃避同源策略,他们分别是<script><link><img>,这三个标签的src\href可以加载其他域的资源。

  • <img>可以做打点统计。
  • <script><link>可以使用 CDN,CDN 基本都是其他域的链接。
  • 另外<script>还可以实现 JSONP,能获取其他域接口的信息

请注意,所有的跨域请求方式,最终都需要信息提供方来做出相应的支持和改动,也就是要经过信息提供方的同意才行,否则接收方是无法得到它们的信息的,浏览器是不允许的。

解决跨域

JSONP

1
2
3
4
5
6
7
8
9
10
11
12
function JSONP(url, cb) {
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = `${url}?callback=${cb}`;
document.querySelector('head').appendChild(script);
}

function dealData1(data) {
console.log('这是getData1的回调:' + data.name);
}

JSONP('api.ytpblog.com/api/v1/xxx', 'dealData1'); // www.somewhere.com/getdata1?callback=dealData1

服务器设置 http header

1
2
3
4
5
6
7
8
9
response.setHeader('Access-Control-Allow-Origin', 'http://api.ytpblog.com/'); // 第二个参数填写允许跨域的域名称,不建议直接写 "*"
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');