实现跨域的三种方式(cors,jsonp,proxy),以及不足

1.利用JSONP实现跨域

主要原理就是是利用script标签跨域不受同源策略(http协议,域名,端口号一致)限制,通过src属性向后台发送一个带有回调参数的get请求,而后获取回调函数中的参数中的数据,同源策略限制表现:cookie,LocalStorage 跨域不能读取修改

最初的jquery就是通过JSONP取巧发送跨域请求的

<script>
    var script = document.createElement('script');
    script.type = 'text/javascript';

// 传参一个回调函数名给后端,方便后端返回时执行这个在前端定义的回调函数
    script.src = 'http://www.domain2.com:8080/login?user=admin&callback=handleCallback';
//返回第一个head元素,添加设置好的script标签
    document.head.appendChild(script);

    // 回调执行函数
    function handleCallback(res) {
        alert(JSON.stringify(res));
    }
 </script>
服务端返回如下(返回时即执行全局函数):

handleCallback({"success": true, "user": "admin"})

jsonp缺点:

  • 由于只是一个html标签,只有get方法,比如图片img通过src去获取资源,只能获取也就无法发送post请求
  • 在请求失败时,不会返回各类http状态码
  • 使用jsonp不安全,回调函数callback参数可能被恶意修改,修改成一些获取例如cookie携带用户信息的请求,那么用户的隐私可能被泄露,这也就时所谓的XXS攻击(解决方法就是替换字符串,防止发送参数为脚本,变成普通文本,也就不会执行脚本)

2.CORS跨域资源共享

先附上一些常见的请求头

  • Accept:可接受的相应内容类型(Content-Type);
  • Accept-Language:可接受响应内容的语言列表;
  • Accept-Charset:可接受的字符集;
  • Accept-Encoding:可接受的响应内容的编码方式;
  • Accept-Datetime:用于表示HTTP协议中需要认证资源的认证信息;
  • Cache-Control:用来指定当前的请求、回复中是否使用缓存机制;
  • Connection:keep-alive/Upgrade客户端(浏览器有限使用的连接类型)
  • Cookie:用于服务器与客户端间的通讯;
  • Content-Length:以8进制表示的请求体的长度;
  • Content-Type:请求体的MIME类型(用于POST和PUT请求中)Content-type:application/x-www-form-urlencoded;
  • Date:发送该消息的日期和时间;
  • Expect:表示客户端服务器做出特定的行为;
  • Referer:表示浏览器所访问的前一个页面,可以认为是之前访问页面的链接将浏览器带到了当前页面。Referer其实是Referrer这个单词,但RFC制作标准时给拼错了,后来也就将错就错使用Referer了。
  • User-Agent:浏览器的身份标识字符串
    响应头
  • Access-Control-Allow-Origin:指定哪些网站可以跨域源资源共享
  • Accept-Ranges:服务器所支持的内容范围
  • Age:响应对象在代理缓存中存在的时间,以秒为单位
  • Cache-Control:通知从服务器到客户端内的所有缓存机制,表示它们是否可以缓存这个对象及缓存有效时间。其单位为秒
  • Connection:针对该连接所预期的选项
  • Content-Disposition:对已知MIME类型资源的描述,浏览器可以根据这个响应头决定是对返回资源的动作,如:将其下载或是打开。
  • Content-Encoding:响应资源所使用的编码类型。
  • Content-Language:响就内容所使用的语言
  • Content-Length:响应消息体的长度,用8进制字节表示;
  • Content-Location:所返回的数据的一个候选位置;
  • Content-Range:如果是响应部分消息,表示属于完整消息的哪个部分
  • Content-Type:当前内容的MIME类型
  • Date:此条消息被发送时的日期和时间(以RFC 7231中定义的"HTTP日期"格式来表示)
  • ETag:对于某个资源的某个特定版本的一个标识符,通常是一个 消息散列;是否更新;
  • Expires:指定一个日期/时间,超过该时间则认为此回应已经过期
  • Set-Cookie:设置HTTP cookie
  • Server:服务器的名称

简单请求

请求方式使用下列方法之一:
GET
HEAD
POST

Content-Type(实际发送数据类型) 的值仅限于下列三者之一:
text/plain(纯文本格式)
multipart/form-data(表单上传文件时的格式)
application/x-www-form-urlencoded(表单编码后的key/value格式)

cors允许浏览器跨源向服务器发送XMLHttpRequeset,前提是浏览器(兼容性)与服务器同时支持才可实现跨域,主要通过后端设置服务器相关cors头部字段,针对一些简单请求(get,head,post)利用Access-Control-Allow-Origin设置允许跨域的源,服务器接收到该源跨域请求则会成功返回,如图

非简单请求

使用了下面任一 HTTP 方法:
PUT(修改,替换服务器资源)
DELETE(删除)
CONNECT(简历资源表示的服务器隧道)
OPTIONS(获取服务器支持的http请求方式)
TRACE(测试)
PATCH(对已知资源进行更新)

Content-Type 的值不属于下列之一:
application/x-www-form-urlencoded multipart/form-data text/plain

对于非简单请求,服务器会先发送一个options请求’预检‘,先查看是否支持该请求方式,支持则会发送请求至后端,不支持则会抛出错误

// 前端代码
var url = 'http://localhost:2333/cors';
var xhr = new XMLHttpRequest();
xhr.open('PUT', url, true);
xhr.setRequestHeader('X-Custom-Header', 'value');
xhr.send();

通过上述非简单请求方式我们可知,遇见是通过options来进行请求的

//预检请求
OPTIONS /cors HTTP/1.1
Origin: localhost:2333
Access-Control-Request-Method: PUT // 表示使用的什么HTTP请求方法
Access-Control-Request-Headers: X-Custom-Header // 表示浏览器发送的自定义字段
Host: localhost:2332
Accept-Language: zh-CN,zh;q=0.9
Connection: keep-alive
User-Agent: Mozilla/5.0...
HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://localhost:2332 // 表示http://localhost:2332可以访问数据
Access-Control-Allow-Methods: GET, POST, PUT      
Access-Control-Allow-Headers: X-Custom-Header    
Content-Type: text/html; charset=utf-8
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain

确定可发送请求之后就和简单请求一样,发送请求,返回数据

请求成功就返回数据,这里附上一些cors字段

(1)Access-Control-Allow-Methods

该字段必需,它的值是逗号分隔的一个字符串,表明服务器支持的所有跨域请求的方法。注意,返回的是所有支持的方法,而不单是浏览器请求的那个方法。这是为了避免多次"预检"请求。

(2)Access-Control-Allow-Headers

如果浏览器请求包括Access-Control-Request-Headers字段,则Access-Control-Allow-Headers字段是必需的。它也是一个逗号分隔的字符串,表明服务器支持的所有头信息字段,不限于浏览器在"预检"中请求的字段。

(3)Access-Control-Allow-Credentials

该字段与简单请求时的含义相同,可选字段,即是否可以发送cookie

(4)Access-Control-Max-Age

该字段可选,用来指定本次预检请求的有效期,单位为秒。

3.利用webpack Proxy代理实现跨域

proxy也就是vue-cli使用的跨域代理配置

原理:proxy工作原理实质上是利用http-proxy-middleware 这个http代理中间件,实现请求转发给其他服务器,当本地发送请求的时候,代理服务器响应该请求,并将请求转发到目标服务器,目标服务器响应数据后再将数据返回给代理服务器,最终再由代理服务器将数据响应给本地

在代理服务器传递数据给本地浏览器的过程中,两者同源,并不存在跨域行为,这时候浏览器就能正常接收数据,通过避开浏览器的同源策略完成跨域请求

  // 配置跨域devServe服务  vite搭建配置跨域就是serve,路径重写也不一致
  devServer: {
    // 配置跨域委托代理Proxy
    proxy: {
      "/path": {
        target: "https://i.maoyan.com", //替换的服务端地址
        changeOrigin: true, //开启代理
        pathRewrite: {
          "^/path": "",
        },
      },
    },

注意:服务器与服务器之间请求数据并不会存在跨域行为,跨域行为是浏览器安全策略限制,并且proxy代理只是针对的开发环境使用

posted @ 2022-10-31 21:40  YYYang333  阅读(858)  评论(0)    收藏  举报