《AngularJS 权威教程》读书笔记,第十六章——XHR实践。
跨域
同源策略允许页面从同一个站点加载和执行特定的脚本。
浏览器全面禁止了页面加载或执行与自身来源不同的域的任何脚本。
感觉这里说的两句话是大错特错的,浏览器只是对 XHR 异步请求有同源策略的限制吧!iframe, script, img,这些标签还不是可以虽然加载域外资源,jsonp 不也是利用了这一点嘛!难道是翻译这本书的人水平太渣。。。
实现跨域请求的三种方式:
- JSONP
- CORS
- 服务器代理
JSONP
JSONP,名字来源:P 代表“填充”或“前缀”。假如在服务器上启用了 CORS(从这里可以看出 CORS 应该是:扩展了 HTTP 请求头实现的,也就说了改进了 HTTP 协议,而新的浏览器才会跟进这些新的改变),在新的浏览器下,跨域文档也可以通过 XMLHttpRequest 享受该服务。在不支持 CORS 的旧浏览器,跨域文档只能通过<script>
元素访问服务:
至于 JSONP 请求的的响应状态码,响应头信息怎么来呢?使用<script>
标签就是相当于利用浏览器自身的网络请求功能请求数据,而我们的 js 是读取不到这种网络请求的响应信息的,所以一般服务器返回 JSONP 响应时会包含一个meta
对象来表示响应头信息。无图无真相:
CORS
近年来,W3C 指定了跨域资源共享来通过标准的方式取代 JSONP。
CORS 规范简单地扩展了标准的 XHR 对象,以允许 JavaScript 发送跨域的 XHR 请求。它会通过遇检查(preflight)来确认是否有权限向目标服务器发送请求。
W3C 指定 CORS 规范时对很多细节进行了抽象,并使其对客户端开发者透明,让开发者可以像发送同域请求一样方便地发送跨域请求。
AngularJS客户端设置
为了在 AngularJS 中使用 CORS,首先需要告诉 AngularJS 我们正在使用 CORS,使用 config 方法在应用模块上设置两个参数以达到此目的。
首先,告诉 AngularJS 使用 XDomain,并从所有的请求中把 X-Request-With 头移出掉(X-Request-With 头默认就是移出掉的,但是再次确认没有坏处),为啥这么操作就是发送 CORS 请求了呢?我也不知道,应该是 AngularJS 的一种约定吧!
服务器端CORS支持
后端服务器必须支持 HTTP 协议的 OPTIONS 方法。
后端服务器响应中 CORS 相关的响应头:
- Access-Control-Allow-Origin:* 表示会接收从任何来源发来的请求
- Acceess-Control-Allow-Credentials:默认情况下 CORS 请求不会发送 cookie。如果服务器返回了这个头,那么就可以通过 withCredentials 设置为 true 来将 cookie 同请求一起发送出去(如果将 $http 发送的请求中的 withCredentials 设置为 true,但服务器没有返回 Access-Control-Allow-Credentials,请求就会失败,反之亦然)。
CORS 请求分为简单和非简单两种类型。
简单请求
啥是简单请求:
- HTTP 请求方法是这三种的某一种:HEAD、GET、POST
- HTTP 请求头只有以下的一种或几种:Accept、Accept-Language、Content-Language、Last-Event-ID、Content-Type(application/x-www-form-urlencoded, multipart/form-data, text/plain)
对于简单请求,浏览器可以不需要使用 CORS 就发送这类请求。简单请求不要求浏览器和服务器之间有任何的特殊通信。
非简单请求
啥事非简单请求呢?不是简单请求的都是非简单请求。
对于非简单请求,尽管在客户端开发者看来没有什么不同,但浏览器会以不同的方式处理它们。浏览器实际上会发送两个请求:预请求和请求。浏览器首先向服务器发送预请求来获得发送请求的许可,只有许可通过了,浏览器才会发送真正的请求。浏览器处理 CORS 的过程是透明的,同简单请求一样,浏览器会给预请求和请求都加上 Origin 头。
预请求过程中的请求:
- 预请求的请求类型是 OPTIONS 类型
- Access-Control-Request-Method:这个头是请求所使用的 HTTP 方法,会始终包含在请求中
- Access-Control-Request-Headers:可选,这个头的值是一个以逗号分隔的非简单头列表,列表中的每个头都会包含在这个请求中
预请求过程中的服务器端处理:
服务器端必须可以接受这个请求,然后检查 HTTP 方法和头的合法性。如果通过了检查,服务器会在响应中添加下面这个头:
- Access-Control-Allow-Origin:值是请求的来源或者星号
- Access-Control-Allow-Methods:这是服务器端可以接受的 HTTP 方法列表,浏览器可以缓存这个列表,以后非简单的 CORS 请求可以不必再次发送预请求
- Access-Control-Allow-Headers:如果设置了 Access-Control-Request-Headers 头,服务器必须在响应中添加同一个头
如果预请求返回了 200 状态码,真正的请求就会发出了。
服务器端代理
最后一个简单粗暴的实现跨域请求的方案就是架设服务器端代理,浏览器客户端的请求有同源策略的限制,但是后台程序的请求却没有任何限制的,所以可以架设一台代理服务器来负责向第三方发送实际的请求。
AJAX请求中使用XML
涨姿势了,异步请求中还可以使用XML格式响应数据,不过前端得需要添加一个可以将XML转换为JSON格式的类库X2JS,不过应该没人闲的蛋疼这么干了吧!