ajax 跨域请求api_vue跨域方案指北

dddc7ebf1492922c38bdb2f9c0706d99.png

跨域是指违背了浏览器同源策略的限制

简单的说,我们通常使用的请求工具都是基于XMLHttpRequest对象构建的,它是严格遵守同源策略的,所以当需要跨域时,基于它的工具就无法工作了,我们需要一些额外的手段来解决这个问题 本文主要对已知的几种跨域方案进行实践和总结

一、jsonp

jsonp虽然不是官方的跨域方案,但它是最早出现的跨域方案,另外不管你是怎么使用jsonp跨域,服务端支持这种跨域是前提

缺点

由于jsonp是使用script、img、iframe没有同源限制的标签,所以它只支持get请求

另外jsonp错误处理机制不完善

优点

jsonp的优点是它可以兼容低版本的浏览器

1.原理

jsonp是使用script、img、iframe没有同源限制的标签,向服务端发送请求,将返回的数据作为指定的回调函数的参数,script标签引入的函数是属于window全局的,所以你只需要在另一个script中指定回调函数,这样就可以获取到服务端数据了

这是个最基础的jsonp跨域例子

// test.html

控制台打印如下

d7f015a9797ee8795f6a188d04eefad4.png

此时在newwork中查看preview,返回的是一个函数,假如回调函数存在的话就执行它

d33ba22625dceec6a5a245843bf1654a.png

上面只是说说它的原理而已,接下来进入正题,vue是如何使用的

2.封装

vue要使用jsonp,可以借助第三方工具包,推荐使用jsonp,假如你喜欢axios风格,用起来肯定得心应手。

a.下载

cnpm i jsonp --save

b.引入

新建一个文件,用来放我们封装的jsonp工具

// http.js

根据jsonp的文档,我们知道jsonp需要三个参数

d5dde607eb8bcf1eb8f59ea02ada223d.png

另外还需要重新定义一个配置对象

var 

然后返回一个Promise风格的jsonp函数,将url作为形参,options作为实参,另外加一个回调函数

// http.js

有的时候,我们还需要给服务端传参数,这时候就需要将参数对象拼接到URL中去,我们也可以将此封装下

// 将Parma参数拼接到url上

所以完整的代码是这样的

import 

3.使用

在我们的接口文件中引入封装好的jsonp,就可以根据自己情况使用了

// api/getTotal.js

接着在要使用的组建中引入接口函数

// list.vue

二、CORS(跨域资源共享)

CORS仍然是使用XMLHttpRequest发送请求,只是多了些字段告诉服务器允许跨域,同样,它也需要服务端的支持

优点

可以访问多种请求方式

处理机制完善

符合http规范,对于复杂请求,多一次验证,安全性更好

缺点

不支持IE10以下浏览器

下面为了说明CORS原理,这里给出一个测试的服务端代码

const 

和一个客户端代码,如果你感兴趣可以将它在纯html页面和vue项目各放一份

let 

1.原理

跨域资源共享(CORS)是http官方推荐的跨域方案,它是一种机制,使用额外的HTTP头来告诉浏览器,让运行在一个origin (domain)上的Web应用被准许访问来自不同源服务器上的指定的资源,这是MDN对CORS的标准定义,简单说是在发送请求的时候添加一个名为origin的字段给服务器,服务在判断它是可以接受的范围,并且返回一个Access-Control-Allow-Origin字段

例如,在上面的例子中,不管是vue项目还是单独的html页面,都可以在控制台看到服务端返回的"hello world",

并且字段如下

// request header

当将服务端的字段值改变为http://localhost:8080,发现只有http://localhost:8080的vue项目可以正常跨域,html页面报错

Access to XMLHttpRequest at 'http://127.0.0.1:8090/' from origin 'null' 
has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header 
has a value 'http://localhost:8080' that is not equal to the supplied origin.

注意,http://localhost:8080和http://127.0.0.1:8080对服务端来说是不一样的

CORS根据是否使用默认支持的字段和方法将请求分为“简单请求”与“非简单请求”,浏览器会根据不同类型作出不同处理,它们的区别是简单请求不会调用验证机制,而非简单请求则会调用验证机制

对于(CORS默认)简单请求,它的请求方法不超过下面三种,头部信息不超过以下字段

(1) 请求方法:
     HEAD
     GET
     POST
(2)HTTP的头信息:
     Accept
     Accept-Language
     Content-Language
     Last-Event-ID
     Content-Type:
         application/x-www-form-urlencoded、 multipart/form-data、text/plain

注意 简单请求:

  1. 不能接收或者发送cookie
  2. 不能使用setRequestHeader()设置自定义头部
  3. 调用getAllResponseHeader()得到的事空字符串

假如我们的需要使用上面列出的以外的方法或者字段,就是属于非简单请求了,对于这种请求,浏览器会先调用Preflighted Request透明服务器的验证机制,使用OPTIONS方法和服务器验证,通过验证,浏览器才会正式请求服务器。

前面说了CORS默认(简单请求)是不支持调用setRequestHeader和getAllResponseHeader,在非简单请求里,可以使用OPTIONS方法突破这种默认限制

// 客户端

这时network中会多出一个验证的请求

a5a4c82bd6d766dc6a8bb022fd4aaba9.png

假如服务端没有设置这个字段权限,那它就会在控制台报错

Request header field x-pingother is not allowed by Access-Control-Allow-Headers in preflight response.

假如你需要发送或者接受cookie,可以将实例的withCredentials属性设为true,同时也需要服务器配合,允许接收带cookie的请求,响应头部信息会返回下面的字段和值

// 客户端

假如服务端将Credentials设置为false,那么客户端会触发onerror程序,并且status为0,responseText为空字符串

bf28e9d278ad03a042526e17754e925f.png
res.setHeader("Access-Control-Allow-Credentials", false);

2.封装

在vue项目中使用axios,对它进行业务的封装

a.下载

cnpm i axios -s

b.引入

新建http/request.js,存放我们封装之后的axios文件

// http/request.js

在项目里通常需要对请求做统一处理,比如,给每个请求带上cookie,对所以的响应作出反应,根据不同的错误状态导入不同的页面,借用axios的拦截器,可以做到我们想要的效果

// 设置拦截器

3.使用

在我们的接口文件中引入封装好的axios,就可以使用了

// api/getTotal.js

接着在要使用的组建中引入接口函数

// list.vue

三、proxy(服务端代理)

在vue项目中,webpack选项devServer有一个proxy属性,通常都是使用这个属性将所有带指定字符串的请求,发送到target目标服务器。查看文档,发现devServer调用了http-proxy-middleware插件,将请求转发给目标服务器。

下面是官网给出的示例

var 

为了说明原理,我自己创建了两个node服务,一个模拟客户端,一个模拟目标服务器

1.原理

在客户端,用http创建一个服务,并返回展示的页面

const 

另外在页面中,可以自己定义或者引用已经写好的ajax,向客户端服务器发送请求,客户端在接受到这个这个请求时,转发给目标服务器,实现如下

<!DOCTYPE html>

目标服务器负责接收不同的url,并分别作出响应

// 目标服务器

这时浏览器控制台可以接收到目标服务器发送的json数据了

f053176e10e359dc8607fcb8ef6c0154.png

2.封装和使用

在设置基础路径之外,我们需要指明跨域的目标服务器地址

devServer

同样是使用axios,封装和使用同cros,只是baseURL不一样,这里只给出完整的代码

// 引入

四、更多方案

除了前面提到的跨域方案,你还可以使用nginx反向代理,它和proxy十分类似,都是访问中间层,由中间层去访问目标服务器

另外还有很多讨巧的方法进行跨域,比如你在页面中使用iframe标签,使用哈希location.hash的方式,进行跨域并且传递数据;也可以使用window.name或者H5的postMessage接口

这些跨域方案在实际使用中偏冷门,我也没有实践过,所以这里这是简单的提到

文章如果有错误的地方,欢迎指出,我会及时改正

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值