关键词:
在工作中,难免会遇到跨域的问题,就像你高高兴兴的带着老婆吃着火锅,啊不对,是匆匆忙忙的在搬砖,突然浏览器告诉你跨域了,意不意外?
既然遇到了,就只能解决他,平时一顿乱操作,也能解决问题,但一直没有好好的来总结。
俗话说的好,知己知彼、百战不殆。我们来看看什么是跨域?谁在搞事情?
原来是浏览器在搞事情,不过,浏览器表示它不想背这个锅:
同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要安全机制。
这是官方的解释,比较拗口,意思就是,为了网页更加安全而设计的安全策略,这个同源策略规定:
如果两个页面的协议,端口(如果有指定)和域名都相同,则两个页面具有相同的源,访问不受限制;否则则为跨源(跨域),限制访问。
浏览器为什么要搞个同源策略呢?
这是为了防止CSRF攻击(Cross-site request forgery),中文名称:跨站请求伪造。谁不怕坐着火车出了城,突然就被麻匪给劫了不是。
既然跨域必须存在,而我们又必须绕不过它,那我们该如何解决呢?
1、JSONP-----需要后端接口配合
利用script、img这样没有跨域限制的标签,来发起请求。
第一版的JSONP
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 </head> 6 <body> 7 <script type=‘text/javascript‘> 8 // 后端返回直接执行的方法,相当于执行这个方法,由于后端把返回的数据放在方法的参数里,所以这里能拿到res。 9 window.jsonpCb = function (res) 10 console.log(res) 11 12 </script> 13 <script src=‘http://localhost:9871/api/jsonp?msg=helloJsonp&cb=jsonpCb‘ type=‘text/javascript‘></script> 14 </body> 15 </html>
封装版:
1 /** 2 * JSONP请求工具 3 * @param url 请求的地址 4 * @param data 请求的参数 5 * @returns Promise<any> 6 */ 7 const request = (url, data) => 8 return new Promise((resolve, reject) => 9 // 处理传参成xx=yy&aa=bb的形式 10 const handleData = (data) => 11 const keys = Object.keys(data) 12 const keysLen = keys.length 13 return keys.reduce((pre, cur, index) => 14 const value = data[cur] 15 const flag = index !== keysLen - 1 ? ‘&‘ : ‘‘ 16 return `$pre$cur=$value$flag` 17 , ‘‘) 18 19 // 动态创建script标签 20 const script = document.createElement(‘script‘) 21 // 接口返回的数据获取 22 window.jsonpCb = (res) => 23 document.body.removeChild(script) 24 delete window.jsonpCb 25 resolve(res) 26 27 script.src = `$url?$handleData(data)&cb=jsonpCb` 28 document.body.appendChild(script) 29 ) 30 31 // 使用方式 32 request( 33 url: ‘http://localhost:9871/api/jsonp‘, 34 data: 35 // 传参 36 msg: ‘helloJsonp‘ 37 38 ).then(res => 39 console.log(res) 40 )
2、空iframe和form配合
因为script标签加载资源的方式就是GET。所以JSONP只能发GET请求,那么我们发送POST请求这么办呢?
1 const requestPost = (url, data) => 2 // 首先创建一个用来发送数据的iframe. 3 const iframe = document.createElement(‘iframe‘) 4 iframe.name = ‘iframePost‘ 5 iframe.style.display = ‘none‘ 6 document.body.appendChild(iframe) 7 const form = document.createElement(‘form‘) 8 const node = document.createElement(‘input‘) 9 // 注册iframe的load事件处理程序,如果你需要在响应返回时执行一些操作的话. 10 iframe.addEventListener(‘load‘, function () 11 console.log(‘post success‘) 12 ) 13 14 form.action = url 15 // 在指定的iframe中执行form 16 form.target = iframe.name 17 form.method = ‘post‘ 18 for (let name in data) 19 node.name = name 20 node.value = data[name].toString() 21 form.appendChild(node.cloneNode()) 22 23 // 表单元素需要添加到主文档中. 24 form.style.display = ‘none‘ 25 document.body.appendChild(form) 26 form.submit() 27 28 // 表单提交后,就可以删除这个表单,不影响下次的数据发送. 29 document.body.removeChild(form) 30 31 // 使用方式 32 requestPost( 33 url: ‘http://localhost:9871/api/iframePost‘, 34 data: 35 msg: ‘helloIframePost‘ 36 37 )
3、CORS
CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)跨域资源共享 CORS 详解。看名字就知道这是处理跨域问题的标准做法。
CORS需要浏览器和服务器同时支持,服务器需做如下设置:
3.1、Access-Control-Allow-Origin 该字段必填。它的值要么是请求时Origin字段的具体值,要么是一个*,表示接受任意域名的请求。例如:
ctx.set(‘Access-Control-Allow-Origin‘, ‘http://localhost:9099‘)
3.2、Access-Control-Allow-Credentials
该字段可选。它的值是一个布尔值,表示是否允许发送Cookie.默认情况下,不发生Cookie,即:false。对服务器有特殊要求的请求,比如请求方法是PUT或DELETE,或者Content-Type字段的类型是application/json,这个值只能设为true。如果服务器不要浏览器发送Cookie,删除该字段即可。例如
ctx.set(‘Access-Control-Allow-Credentials‘, true)
3.3、Access-Control-Allow-Methods 该字段必填。它的值是逗号分隔的一个具体的字符串或者*,表明服务器支持的所有跨域请求的方法。注意,返回的是所有支持的方法,而不单是浏览器请求的那个方法。这是为了避免多次"预检"请求。例如:
ctx.set(‘Access-Control-Request-Method‘, ‘PUT,POST,GET,DELETE,OPTIONS‘)
3.4、Access-Control-Expose-Headers 该字段可选。CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想拿到其他字段,就必须在Access-Control-Expose-Headers里面指定。例如:
ctx.set(‘Access-Control-Allow-Headers‘, ‘Origin, X-Requested-With, Content-Type, Accept, t‘)
3.5、Access-Control-Max-Age
该字段可选,用来指定本次预检请求的有效期,单位为秒。在有效期间,不用发出另一条预检请求。
前端:
fetch(`http://localhost:9871/api/cors?msg=helloCors`, // 需要带上cookie credentials: ‘include‘, // 这里添加额外的headers来触发非简单请求 headers: ‘t‘: ‘extra headers‘ ).then(res => console.log(res) )
4、代理
我们使用Nginx作为我们的代理服务器。Nginx配置
server # 监听9099端口 listen 9099; # 域名是localhost server_name localhost; #凡是localhost:9099/api这个样子的,都转发到真正的服务端地址http://localhost:9871 location ^~ /api proxy_pass http://localhost:9871;
Nginx配置好之后,前端什么也不用干,正常请求就行,Nginx会把请求转发到真正的地址。
现在,跨域对你来说,应该不是事儿了吧,可以开开心心的吃火锅了。
关于单元测试的那些事儿,mockito都能帮你解决(代码片段)
摘要:相信每一个程序猿在写UnitTest的时候都会碰到一些令人头疼的问题:如何测试一个rest接口;如何测试一个包含客户端调用服务端的复杂方法;如何测试一个包含从数据库读取数据的复杂方法。。。这些问题m... 查看详情
cors——跨域请求那些事儿
在日常的项目开发时会不可避免的需要进行跨域操作,而在实际进行跨域请求时,经常会遇到类似No‘Access-Control-Allow-Origin‘headerispresentontherequestedresource.这样的报错。这样的错误,一般是由于CORS跨域验证机制设置不正确导致的... 查看详情
ios消息推送那些事儿(代码片段)
关于iOS消息推送的文章,网上其实非常多,但为什么我们还要写这么一篇呢?又是准备从哪些角度去讲述iOS的消息推送?iOS的推送功能的散乱复杂,在于不同操作系统版本、用户授权状态、App的不同生命周期状态以及推送的类型... 查看详情
详解viewmodel的那些事儿(代码片段)
引言关于ViewModel,Android开发的小伙伴应该都非常熟悉,无论是新项目还是老项目,基本都会使用到。而ViewModel作为JetPack核心组件,其本身也更是承担着不可或缺的作用。因此,了解ViewModel的设计思想更是每个... 查看详情
linux——万字总结用户与组的权限那些事儿!建议收藏!(代码片段)
...0c;客官点关注,收藏,订阅一键三连吧❤😜 关于用户与组第一期总结:Linux——万字总结用户与组相关知识!建议收藏!目录权限有哪些?关于权限的那些命令chmodchown chattr:文件或目录的隐藏属... 查看详情
[apue]linux文件访问权限那些事儿(代码片段)
史上最全的关于linux文件权限的总结,出于经典而胜于经典,经过重新梳理,辅以shell脚本用例,以全新的视角呈现在你面前前言说到linux上的文件权限,其实我们在说两个实体,一是文件,二是进程。一个进程能不能访问一个文... 查看详情
git关于git那些事儿
1、关于Git那些事儿https://github.com/FrankKai/FrankKai.github.io/issues/39 查看详情
关于arraylist的那些事
ArrayList初始化-Java那些事儿ArrayList初始化-Java那些事儿专栏ArrayList底层数组扩容原理-Java那些事儿专栏时间复杂度-Java那些事儿专栏三顾ArrayList-Java那些事儿专栏 查看详情
算法零基础学习关于素数的那些事儿(代码片段)
文章目录关于素数用程序判定一个数是否是素数使用素数的定义优化一推荐题目筛选出n之内的所有素数枚举法埃氏筛📖核心思想👨💻代码推荐题目关于素数素数,又称为质数。它是指那些只包含1和它本身两... 查看详情
fastdfs运维友好那些事儿(代码片段)
FastDFS运维友好那些事儿本篇文章转载于FastDFS作者余庆大佬的FastDFS分享与交流公众号。FastDFS运维友好那些事儿(一)FastDFS运维友好那些事儿(二)最近有人在FastDFSQQ技术交流群里爆料,说网上有人吐槽FastDFS... 查看详情
诊断协议那些事儿(代码片段)
诊断协议那些事儿本专栏将以ISO14229、15765-2为基础深入介绍诊断那些事儿,从故障定位到软件刷写……重点掌握各个服务的功能、报文格式,为后续功能开发打下基础!提示:可参考目录索引进行学习一、UDS是什... 查看详情
关于http和https的那些事儿(代码片段)
一:什么是协议?网络协议是计算机之间为了实现网络通信而达成的一种“约定”或者“规则”,有了这种约定,不同厂商的生产设备,以及不同操作系统组成的计算机之间,就可以实现通信。二:HTTP协议是什么?H... 查看详情
关于"尾调用优化"的那些事儿
大家好,我是CoderBin前言本文将给大家介绍JavaScript函数中关于尾调用优化的优点与写法,助你提升编码能力 查看详情
注解的那些事儿|注解的使用(代码片段)
...章首发于【博客园-陈树义】,点击跳转到原文《注解的那些事儿(三)|注解的使用》学会了如何定义自定义注解,那还要会用起来才行。其实自定义注解使用也非常简单,像我们上篇文章定义的一个Sweet注解。public@interfaceSweetSt... 查看详情
docker那些事儿关于容器底层技术的奥秘
@toc 查看详情
docker那些事儿关于namespace隔离机制的奥秘
@toc 查看详情
工具类excel导出那些事儿(代码片段)
接上一篇博客,继续介绍双标题导出./***双标题excel导出*@paramresponse*@paramfileName文件名*@paramsheetNamesheet页名*@paramfirstTitle第一行表头标题*@paramtitle第二行标题*@paramcontent每一列对应值*@paramlist单元格下拉选项(可... 查看详情
ios单元测试的那些事儿(代码片段)
iOS单元测试的那些事儿作为客户端开发,很多时候我们过多的关注于功能的测试,而忽略标准的单元测试。其实,单元测试是保障项目稳定性的最有效且成本最低的测试方式。越偏向底层服务的代码,越需要使用单元测试来对可... 查看详情