首钢建设二建设公司网站,网站模板与网站定制版的区别,wordpress如何导航网站,网站建设类公司新闻前言 最近博主在字节面试中遇到这样一个面试题#xff0c;这个问题也是前端面试的高频问题#xff0c;作为一名前端开发工程师#xff0c;我们日常开发中与后端联调时一定会遇到跨域的问题#xff0c;只有处理好了跨域才能够与后端交互完成需求#xff0c;所以深入学习跨域… 前言 最近博主在字节面试中遇到这样一个面试题这个问题也是前端面试的高频问题作为一名前端开发工程师我们日常开发中与后端联调时一定会遇到跨域的问题只有处理好了跨域才能够与后端交互完成需求所以深入学习跨域是很有必要的博主在这给大家细细道来。 作者简介程序员小豪全栈工程师热爱编程曾就职于蔚来、腾讯现就职于某互联网大厂技术栈Vue、React、Python、Java 本文收录于小豪的前端系列专栏后续还会更新前端入门以及前端面试的一些相关文章手把手带你从零学习前端到面试找工作并如果有想进入前端领域工作的同学这个前端专栏会对你有所帮助欢迎关注起来呀 本人也会持续的去关注AIGC以及人工智能领域的一些动向并总结到博客中大家感兴趣的可以关注一下我的人工智能专栏 云原生的入门学习系列大家有兴趣的可以看一看 本文目录 什么是跨域跨域产生原因非同源会出现的限制 如何跨域CORS请求简单请求基本流程withCredentials 属性 非简单请求预检请求预检请求的回应浏览器的正常请求和回应 与JSONP的比较 nginx反向代理解决跨域前端常用JSONPpostMessage总结 什么是跨域
首先一个url是由协议、域名、端口 三部分组成。一般端口默认80 如https://blog.xxx.cn:80
当一个请求url的协议、域名、端口三者之间的任意一个与当前页面url不同即为跨域。 例如:
当前页面url被请求页面url是否跨域原因http://www.xxx.com/http://www.xxx.com/index.html否同源协议、域名、端口号相同http://www.xxx.com/https://www.xxx.com/index.html跨域协议不同http/httpshttp://www.xxx.com/http://www.baidu.com/跨域主域名不同test/baiduhttp://www.xxx.com/http://xxx.com/跨域子域名不同www/xxxhttp://www.xxx.com:8080/http://www.xxx.com:7001/跨域端口号不同8080/7001
————————————————
跨域产生原因
出于浏览器的同源策略限制。同源策略Same Orgin Policy是一种约定它是浏览器核心也最基本的安全功能它会阻止一个域的js脚本和另外一个域的内容进行交互如果缺少了同源策略浏览器很容易受到XSS、CSFR等攻击。 所谓同源即在同一个域就是两个页面具有相同的协议protocol、主机host和端口号port。
非同源会出现的限制
无法读取非同源网页的cookie、localstorage等无法接触非同源网页的DOM和js对象无法向非同源地址发送Ajax请求
如何跨域
CORS请求
浏览器将cors请求分为两类简单请求和非简单请求
只要同时满足以下两大条件就属于简单请求
请求方法是以下三种方法之一 HEADGETPOST HTTP的头信息不超出以下几种字段 AcceptAccept-LanguageContent-LanguageLast-Event-IDContent-Type只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
简单请求
基本流程
简单请求浏览器都是直接发出cors请求其实就是在头信息中加一个Origin字段
GET /cors HTTP/1.1
Origin: http://api.bob.com
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...Origin字段就是用来说明本次请求来自哪个源服务器根据这个值决定是否同意本次请求
如果Origin指定的源不在许可范围内服务器会返回一个正常的http回应这个回应就不包含Access-Control-Allow-Origin那么就说明本次请求出错了这个错误无法通过状态码识别因为http回应的状态码可能是200。
如果Origin指定域名在许可范围内服务器返回的响应就会多出几个头信息字段
Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: FooBar
Content-Type: text/html; charsetutf-8上面的请求头信息中有三个是和cors请求有关系的都以Access-Control-开头 Access-Control-Allow-Origin 这个字段是必须的它的值要么是请求时Origin字段的值要么是*表示接受任意域名的请求 Access-Control-Allow-Credentials 这个字段的值类型是bool类型的表示是否允许发送cookie默认情况下cookie不包含在cors请求中设为true Access-Control-Expose-Header 该字段可选。CORS请求时XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想拿到其他字段就必须在Access-Control-Expose-Headers里面指定。上面的例子指定getResponseHeader(FooBar)可以返回FooBar字段的值。
withCredentials 属性
上面说到CORS请求默认不发送cookie和http认证信息。如果要把cookie发到服务器一方面要服务器同意指定Access-Control-Allow-Credentials字段
Access-Control-Allow-Credentials: true还要浏览器同意开发者必须在ajax请求中打开withCredentials属性:
var xhr new XMLHttpRequest();
xhr.withCredentials true;需要注意的是如果要发送CookieAccess-Control-Allow-Origin就不能设为星号必须指定明确的、与请求网页一致的域名。同时Cookie依然遵循同源政策只有用服务器域名设置的Cookie才会上传其他域名的Cookie并不会上传且跨源原网页代码中的document.cookie也无法读取服务器域名下的Cookie。
非简单请求
预检请求
非简单请求是对服务器有特殊请求的请求比如请求方法为PUT或DELETE或者Content-Type字段类型是application/json
非简单请求的cors请求会在正式通信前增加一次HTTP查询请求称为“预检请求”
这个预检请求就是浏览器向服务器询问当前域名是否在服务器的白名单中以及可以使用哪些请求方法和请求头字段只有得到肯定回复浏览器才会发出正式的XMLHttpRequest请求否则就报错
浏览器发送请求的代码
var url http://api.alice.com/cors;
var xhr new XMLHttpRequest();
xhr.open(PUT, url, true);
xhr.setRequestHeader(X-Custom-Header, value);
xhr.send();上面请求的方法是PUT并且还发送了一个自定义头部字段X-Custom-Header
浏览器发现这是一个非简单请求就发出一个预检请求这个请求的头部信息如下
OPTIONS /cors HTTP/1.1
Origin: http://api.bob.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...预检请求用的请求方法是OPTIONS表示这个请求是用来询问的。头信息里面关键字段是Origin表示请求来自哪个源。
还有两个特殊字段 Access-Control-Request-Method 这个字段是必须的用来列出浏览器CORS请求会用的http方法 Access-Control-Request-Headers 该字段是一个逗号分隔的字符串指定浏览器CORS请求会额外发送的头信息字段上例是X-Custom-Header。
预检请求的回应
服务器收到预检请求以后检查了Origin、Access-Control-Request-Method和Access-Control-Request-Headers字段以后确认允许跨源请求就可以做出回应。
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://api.bob.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Content-Type: text/html; charsetutf-8
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout2, max100
Connection: Keep-Alive
Content-Type: text/plain1Access-Control-Allow-Methods
该字段必需它的值是逗号分隔的一个字符串表明服务器支持的所有跨域请求的方法。注意返回的是所有支持的方法而不单是浏览器请求的那个方法。这是为了避免多次预检请求。
2Access-Control-Allow-Headers
如果浏览器请求包括Access-Control-Request-Headers字段则Access-Control-Allow-Headers字段是必需的。它也是一个逗号分隔的字符串表明服务器支持的所有头信息字段不限于浏览器在预检中请求的字段。
3Access-Control-Allow-Credentials
该字段与简单请求时的含义相同。
4Access-Control-Max-Age
该字段可选用来指定本次预检请求的有效期单位为秒。上面结果中有效期是20天1728000秒即允许缓存该条回应1728000秒即20天在此期间不用发出另一条预检请求。
浏览器的正常请求和回应
一旦服务器通过了预检请求以后每次浏览器正常的CORS请求就都跟简单请求一样会有一个Origin头信息字段。服务器的回应也都会有一个Access-Control-Allow-Origin头信息字段。
下面是预检请求之后浏览器的正常CORS请求。
PUT /cors HTTP/1.1
Origin: http://api.bob.com
Host: api.alice.com
X-Custom-Header: value
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...上面头信息的Origin字段是浏览器自动添加的。
下面是服务器正常的回应
Access-Control-Allow-Origin: http://api.bob.com
Content-Type: text/html; charsetutf-8上面头信息中Access-Control-Allow-Origin字段是每次回应都必定包含的。
与JSONP的比较
CORS与JSONP的使用目的相同但是比JSONP更强大。
JSONP只支持GET请求CORS支持所有类型的HTTP请求。JSONP的优势在于支持老式浏览器以及可以向不支持CORS的网站请求数据。
nginx反向代理解决跨域前端常用
前端通过nginx代理将前端的请求转发到真正的后端域名上就避免跨域了
nginx配置
server{# 监听9099端口listen 9099;# 域名是localhostserver_name localhost;#凡是localhost:9099/api这个样子的都转发到真正的服务端地址http://localhost:9871 location ^~ /api {proxy_pass http://localhost:9871;}
}JSONP
在HTML标签里一些标签比如script、img这样的获取资源的标签是没有跨域限制的所以可以利用他们发去跨域请求这就叫jsonp
后端
// 处理成功失败返回格式的工具
const {successBody} require(../utli)
class CrossDomain {static async jsonp (ctx) {// 前端传过来的参数const query ctx.request.query// 设置一个cookiesctx.cookies.set(tokenId, 1)// query.cb是前后端约定的方法名字其实就是后端返回一个直接执行的方法给前端由于前端是用script标签发起的请求所以返回了这个方法后相当于立马执行并且把要返回的数据放在方法的参数里。ctx.body ${query.cb}(${JSON.stringify(successBody({msg: query.msg}, success))})}
}
module.exports CrossDomain前端
!DOCTYPE html
htmlheadmeta charsetutf-8/headbodyscript typetext/javascript// 后端返回直接执行的方法相当于执行这个方法由于后端把返回的数据放在方法的参数里所以这里能拿到res。window.jsonpCb function (res) {console.log(res)}/scriptscript srchttp://localhost:9871/api/jsonp?msghelloJsonpcbjsonpCb typetext/javascript/script/body
/html其实就是在发送请求的链接带上一个cb的参数这个cb就是script里的一个函数名称然后后端将这个函数名称取出来将要返回的数据放入这个函数的参数里后端返回这个函数给前端前端直接执行。
postMessage
window.postMessage(message,targetOrigin) 方法是html5新引进的特性可以使用它来向其它的window对象发送消息无论这个window对象是属于同源或不同源目前IE8、FireFox、Chrome、Opera等浏览器都已经支持window.postMessage方法。
调用postMessage方法的window对象是指要接收消息的那一个window对象该方法的第一个参数message为要发送的消息类型只能为字符串第二个参数targetOrigin用来限定接收消息的那个window对象所在的域如果不想限定域可以使用通配符 * 。
需要接收消息的window对象可是通过监听自身的message事件来获取传过来的消息消息内容储存在该事件对象的data属性中。
// 发送消息端
window.parent.postMessage(message, http://test.com)
// 接收消息端
var mc new MessageChannel()
mc.addEventListener(message, event {
var origin event.origin || event.originalEvent.originif (origin http://test.com) {console.log(验证通过)}
})总结
各位看官老爷们好小豪已经建立了技术交流群如果你很感兴趣可以私信我加入我的社群。
社群中不定时会有很多活动例如学习资料分享、大厂面经分享、技术讨论、行业大佬创业杂谈等等。
本人目前是在互联网大厂正式工作也有过多个大厂的工作经历加入社群也会有简历修改辅导模拟面试手把手项目实战教学大厂工作内推机会以及大厂面试题解析分享等福利。
社群方向很多相关领域有Web全栈前后端、人工智能、AIGC、自媒体变现、前沿科技文章分享、论文精读等等。
不管你是多新手的小白都欢迎你加入社群中讨论、聊天、分享加速助力你成为下一个技术大佬也随时欢迎您跟我沟通一起交流一起成长。变现、进步、技术、资料、项目、你想要的这里都会有
网络的风口只会越来越大风浪越大鱼越贵欢迎您加入社群~一个人可以或许可以走的很快但一群人将走的更远
想都是问题做都是答案行动起来吧欢迎评论区or后台与我沟通交流也欢迎您扫描下方二维码直接加入到我的交流社群(微信adcoderhao)