首页 > 其他分享 >重学HTTP:理解同源策略和CORS

重学HTTP:理解同源策略和CORS

时间:2023-07-24 20:13:46浏览次数:37  
标签:重学 浏览器 请求 预检 服务器 CORS HTTP 跨域

​每次遇到跨域、代理、CORS这几个词都懵懵的,我决定一次把他们都搞明白,以后遇到他们再也不用害怕了。


一、什么是同源策略?

同源策略是在1995年由 Netscape公司引入到浏览器的,目前所有浏览器都支持,它是浏览器最重要的安全保障,目的是严格管理不同网站间相互的资源访问(严格来说是不同“源”之间)。

什么是“源”,“源”是指:协议+域名+端口号,这三个必须都相同,才算是同源。假设我们的网站是:http://www.abc.com,那么:

http://www.abc.com/a 同源(与路径无关)
http://www.abc.com:80 同源(80端口是http默认端口)
http://www.Abc.com 同源(url忽略大小写)
https://www.abc.com 不同源(协议不同)
http://www.abc.com:81 不同源(端口不同)
http://abc.com 不同源(域名不同)
http://api.abc.com 不同源(域名不同)
http://api.www.abc.com 不同源(域名不同)
http://220.188.32.45:80 不同源(自己服务器的IP也不行)

 

注意,同源策略只存在于浏览器之中,服务端发出的HTTP请求是不受限制的。

 

二、跨源不止AJAX

提到跨域(跨源),一般都是我们在写AJAX的时候会涉及。其实,web中还有很多别的行为也会跨域,浏览器对这些行为有不同的默认处理方式,常见的有以下这些(注意,浏览器的处理方式未经严格验证,仅供参考):

<script>、<link>、<img>、<video>、<object>、background的url() 根据我们的经验,对这些浏览器是允许跨域访问的,css好像需要设置一下content-type,这个用到时再说
@font-face引入字体 这个部分浏览器是不支持跨域的,需要CORS
cookie 可以通过把cookie写入到一级域名,二级域名就可以访问了,其余情况不允许
localStorge和indexDB 不允许跨域
form提交 允许跨域
AJAX 不允许跨域
<iframe> 过时的东西,不讨论了

 

三、为什么需要同源策略?

我是这么理解的:网站获取自己的资源当然没问题,可如果想拉取其他网站的资源,这种行为等于“偷”啊!你用我的浏览器去“偷”人家的东西,那万一出了事,我是要承担责任的!那可不行,我得禁止你“偷”人家的东西,于是就有了同源策略。

以下我们只讨论AJAX。并且其实AJAX跨域也有:JSONP、WebSocket、CORS三种方法,由于本人只对CORS感兴趣,所以只讨论CORS。

 

四、什么是CORS?

很显然,完全禁止跨源也不行啊,现在很多应用前端和服务本来就不在一个服务器上。那怎么办呢?除非,服务器你自己告诉我,这个资源允不允许这个源访问。怎么告诉我呢?在响应头里。这种通过允许服务器自定义不同源对自己资源的访问权限,然后浏览器据此来拦截或放行的方式,就叫CORS。

这儿我们可以得到一个重要的信息,就是浏览器拦截跨域请求,是在响应阶段,也就是响应返回到浏览器之后,再决定是否拦截。自然会产生的疑问是,为什么不在请求阶段就拦截呢?在请求阶段就拦截的话,如何知道服务器那边到底允不允许呢?这样等于彻底禁止了跨域资源请求,显然不行。

 

四、简单请求和复杂请求

浏览器把跨域的AJAX分为:简单请求和复杂请求。具体定义如下,同时满足以下3项(其实还有其他2项,只是一般用不到)要求的,就是简单请求,其余的都是复杂请求:

(1) 请求方法是以下三种方法之一:

  • HEAD
  • GET
  • POST

(2)HTTP的头信息不超出以下几种字段:

 

  • Accept

 

  • Accept-Language
  • Accept-Encoding
  • Content-Language
  • Content-Type
(3)Content-Type只限于以下三个值:
  • text/plain
  • multipart/form-data
  • application/x-www-form-urlencoded

 

 

是不是有点眼熟?这三种Content-Type正是Form表单的三种数据提交格式。这主要是因为,在没有AJAX的时代,我们通过Form表单的方式来提交数据,做过Form表单提交的同学都知道,这个是允许跨域的。所以为了向前兼容,浏览器就把Form表单可以模拟的AJAX称为简单请求,反之就是复杂请求。

关于这个其实有更深层次的理解,大家可以在知乎搜索“为什么跨域的post请求区分为简单请求和非简单请求和content-type相关?”,看看“贺师俊”大佬的回答。

与简单请求不同的是,复杂请求会在正式请求之前,先发送一个OPTIONS请求到服务器,称为“预检”,在获得服务器的允许后,才会发送正式请求。

 

五、什么是预检请求?

那么问题来了,既然是响应阶段才拦截,也就是说,不管这个跨域访问服务器允不允许,都不影响它真实的到达服务器,在服务器“兜了一圈”。如果这个请求是GET还好,只不过是来“观光”的,不会产生啥影响,但如果是POST、PUT之类的请求,本身往往是会修改服务器资源的,即便响应结果在到达浏览器后被拦截了,对服务器的影响也已经发生了,无法挽回了。虽然服务器也可以写代码直接拒绝这些请求,但浏览器不能指望服务器自己把这些都做好啊。那怎么办呢?浏览器也有办法,在发出真实请求之前,先发一个“预检请求”,先问服务器这个请求是否被允许?服务器允许之后,才发送正式请求。这种方式,就叫“预检”。

 

六、预检请求能不能省了?

如果每次复杂请求都要先发送一次预检,也太麻烦了。很自然的会想,有没有办法来避免每次都要预检?有办法,服务器可以在OPTIONS请求的响应里加一个Access-Control-Max-Age响应头,告诉浏览器这个预检的结果可以被缓存多久。比如Access-Control-Max-Age:86400,则在一天之内,对同一个请求,浏览器不用重复发送预检请求了。什么?你想再简单一点,能不能告诉浏览器“这个网站朕准了,发送一次之后都不用发送预检了”?抱歉,做不到。预检能省来源于浏览器对预检请求结果的缓存,而这个缓存的键,是:URL+请求方法+请求头。所以,只能针对单个请求,利用缓存在一定时间内只发送一次预检。

 

以上是我对跨域和CORS的理解,有错误之处欢迎指出,非常感谢!

 

标签:重学,浏览器,请求,预检,服务器,CORS,HTTP,跨域
From: https://www.cnblogs.com/luzeyu/p/17578217.html

相关文章

  • 【网络编程】基础知识(Web Server和HTTP协议)
    WebServer一个WebServer就是一个服务器软件(程序),或者是运行这个服务器软件的硬件(计算机)。其主要功能是通过HTTP协议与客户端(通常是浏览器(Browser))进行通信,来接收,存储,处理来自客户端的HTTP请求,并对其请求做出HTTP响应,返回给客户端其请求的内容(文件、网页等)或返回一个Error......
  • HTTP请求时哪些请求头是默认携带的?
    提起HTTP的请求头和响应头总是一头雾水,因为总是看上去一大堆,好多还不知道是什么意思。今天我们先研究请求头,我就想,如果我们能弄清楚,在我们什么都不做的情况下,一个最简单的HTTP请求会携带哪些请求头,那么复杂的情况无非是在这上面做加法,我们对请求头就能做到心中有数了。我从以下4......
  • 利用Nginx http_image_filter_module模块来裁剪过大的图片
    http_image_filter_module是nginx提供的集成图片处理模块,支持nginx-0.7.54以后的版本,在网站访问量不是很高磁盘有限不想生成多余的图片文件的前提下可,就可以用它实时缩放图片,旋转图片,验证图片有效性以及获取图片宽高以及图片类型信息,由于是即时计算的结果,所以网站访问量大的话,不建......
  • 忽略证书的HTTPS请求实现
    publicstaticvoidhttpsTest(StringhttpUrl){//忽略证书的https请求try{SSLContextsslContext=newSSLContextBuilder().loadTrustMaterial(null,newTrustStrategy(){@OverridepublicbooleanisTrusted(X509Certificate[......
  • httprunner
    httprunner(仅作为个人笔记,如有雷同,请联系删除。。)https://www.cnblogs.com/aichixigua12/p/13162479.htmlHttpRunner是一款面向HTTP(S)协议的通用测试框架,只需编写维护一份YAML/JSON脚本,即可实现自动化测试、性能测试、线上监控、持续集成等多种测试需求。1、特点:继承Requ......
  • mac os socks5转http proxy
    1.使用homebrew安装privoxy,但安装时报错:https://juejin.cn/post/6961616069941264415homebrew执行brewupdate报错Error:homebrew-coreisashallowclone.To`brewupdate`,firstrun:git-C/usr/local/Homebrew/Library/Taps/homebrew/homebrew-corefetch--uns......
  • HttpClient-请求参数
    demo:packagetest;importorg.apache.http.client.methods.CloseableHttpResponse;importorg.apache.http.client.methods.HttpGet;importorg.apache.http.impl.client.CloseableHttpClient;importorg.apache.http.impl.client.HttpClients;importorg.apache.htt......
  • 快速检测HTTP代理IP是否有效的方法及python代码示例
     1.使用在线代理检测工具:有许多免费的在线代理检测工具可用,如ProxyChecker、ProxyScrape等。只需将待检测的代理IP和端口输入工具中,点击开始检测,即可迅速获得代理的可用性和匿名性等信息。 2.使用命令行工具进行检测:在命令行中使用curl命令来测试代理的可用性。例如,输入命令"......
  • SpringBoot基于Spring Security的HTTP跳转HTTPS
    简单说说之所以采用SpringSecurity来做这件事,一是SpringSecurity可以根据不同的URL来进行判断是否需要跳转(不推荐),二是不需要新建一个TomcatServletWebServerFactoryBean,新建这个Bean可能会导致SpringBoot关于Server的配置失效。三是网上大部分流传的通过实现WebServerFactor......
  • 【遇到一个神奇的问题】暂未想到原因,http.Post 传入 nil参数正确,但是传输值为 nil 的
    出错的代码如下:funcgetEab(ctxcontext.Context,credentialsJSONstring,old*externalAccountKeyResp)(*externalAccountKeyResp,error){//inithttpclient// varpostData*bytes.Reader=nil ifold!=nil{ buf,_:=json.Marshal(old) postData......