科普文:HTTP1.1协议【OPTIONS/204、CORS跨域】

384 篇文章 1 订阅
345 篇文章 1 订阅

概叙

科普文:软件架构Nginx系列之【CORS和Nginx跨域配置详解】-CSDN博客

同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。

所谓的“同源策略”,最早是由 Netscape公司提出的一个安全策略,后来这就成为了浏览器最核心也最基本的安全功能,现在所有支持 JavaScript 的浏览器都会使用这个策略。

在同源策略中,要求 域名、协议、端口 3部分都要相同

前面文章我们在Nginx跨域配置时,针对Option请求,给出的响应是204,即无响应体的响应。其实Option就是浏览器处理“同源策略”的一种探测机制,即服务器是否允许“同源策略”,以及“同源策略”的支持规则。

204:No Content

             请求处理成功,但是没有数据实体返回,也不允许有实体返回。
比如说HEAD请求,可能就会返回204 No Content,因为HEAD就是只获取头信息。
这里简单提一下205 Reset Content,和204 No Content的区别是不但没有数据实体返回,
而且还需要重置表单,方便用户再次输入。

HTTP OPTIONS请求是一种用于获取有关服务器支持的HTTP方法和请求URL的信息的请求。
它通常用于跨域资源共享(CORS)中,以确定是否允许跨域请求。
当客户端发送一个OPTIONS请求时,服务器可以返回不同的状态代码作为响应。

意外的HTTP OPTIONS请求状态代码204表示服务器成功处理了请求,并且不需要返回任何实体主体。
这意味着服务器已经满足了客户端的预检请求,并且没有其他内容需要返回。

现在我们已经知道了跨域问题的由来,那又该如何解决呢?

在前后端分离模式中,跨域问题可以分别由前端和后端两个团队来共同解决。

另外一个问题:GET请求本身不会因为跨域而产生问题,为啥,上面的Nginx跨域配置要包含GET方法?

前端解决跨域的方式

  • <script>标签是不受跨域影响,只要herf,src属性的标签都不收跨域的影响
  • 利用JSONP
  • ExpressJS :意外的HTTP OPTIONS请求状态代码204

ExpressJS是一个基于Node.js的Web应用程序框架,它简化了构建Web应用程序的过程。它提供了一组强大的功能和工具,使开发人员能够快速构建可靠且高效的Web应用程序。

HTTP OPTIONS请求是一种用于获取有关服务器支持的HTTP方法和请求URL的信息的请求。它通常用于跨域资源共享(CORS)中,以确定是否允许跨域请求。当客户端发送一个OPTIONS请求时,服务器可以返回不同的状态代码作为响应。

意外的HTTP OPTIONS请求状态代码204表示服务器成功处理了请求,并且不需要返回任何实体主体。这意味着服务器已经满足了客户端的预检请求,并且没有其他内容需要返回。

ExpressJS可以通过中间件来处理HTTP OPTIONS请求,并返回状态代码204。以下是一个示例代码:

const express = require('express');
const app = express();

// 处理OPTIONS请求
app.options('/', (req, res) => {
  res.sendStatus(204);
});

// 其他路由和处理程序...

// 启动服务器
app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

在上面的示例中,当收到根路径的OPTIONS请求时,服务器将返回状态代码204。这表明服务器已成功处理了请求,并且不需要返回任何内容。

ExpressJS的优势在于它的简洁性和灵活性。它提供了丰富的路由和中间件功能,使开发人员能够轻松处理各种HTTP请求和响应。此外,ExpressJS还有大量的社区支持和文档资源,使学习和使用变得更加容易。

ExpressJS的应用场景包括但不限于:

  1. 构建RESTful API:ExpressJS提供了简单而强大的路由功能,使开发人员能够轻松构建符合RESTful设计原则的API。
  2. Web应用程序开发:ExpressJS可以用于构建各种类型的Web应用程序,包括单页应用程序(SPA)、多页应用程序和博客等。
  3. 微服务架构:ExpressJS可以作为微服务架构中的一个服务组件,用于处理特定的业务逻辑。

JSONP能实现的跨域的原理:

  • 底层利用script实现,发送请求的传递callback的参数;
  • 服务端可以到这个参数,给这个参数加上一个()然后直接返回给浏览器;
  • 浏览器接收到返回的内容后就会解析成一个js的函数调用,前提先要定义这个函数。

后端解决跨域的方式

  • Nginx等web服务器配置跨域请求
  • @CrossOrigin:在响应头中添加一个地址;
  • 在SpringMVC的配置文件中进行配置。
<mvc:cors>
    <mvc:mapping path="/**" allowed-origins="*"
       allowed-methods="POST, GET, OPTIONS, DELETE, PUT,PATCH"
       allowed-headers="Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With"
       allow-credentials="true"/>
</mvc:cors>

Get方法为啥也要配置跨域?

​‌HTTP GET请求本身不会因为跨域而产生问题。‌这是因为HTTP GET请求通常被认为是简单请求,不受同源策略的限制。

然而,当GET请求的Content-Type设置为JSON,即非简单请求时,可能会遇到跨域问题。这是因为当请求中包含自定义头信息(如token)时,该请求就不再被认为是简单的GET请求,从而可能触发CORS(跨域资源共享)策略的检查,导致跨域问题‌。

跨域问题的产生主要源自浏览器的同源策略,它要求访问的资源必须位于与当前页面相同的源(即相同的协议、域名和端口号)‌。

然而,对于GET请求,如果没有携带自定义头信息(如token),则不会被视为非简单请求,因此不会因为跨域而受到限制。

例如,图片资源通过img标签加载时,即使图片地址来自其他域名,也不会因为跨域而产生问题,因为这种GET请求不包含自定义头信息‌。

解决跨域问题的方法包括使用JSONP和CORS。JSONP通过动态创建script标签来实现跨域访问,而CORS需要在服务器端设置Access-Control-Allow-Origin等响应头,以允许跨域访问‌。

综上所述,虽然GET请求本身不会因为跨域而产生问题,但在特定条件下(如携带自定义头信息),可能会遇到跨域限制。 ​

Get请求  是否会有跨域问题?是否要在请求前,发送Option请求?

跨域问题主要是由于浏览器安全策略的限制,当请求的地址的域名或端口和当前访问的域名或端口不一样,并且发送的是XHR(XMLHttpRequest)请求时,就会产生跨域问题。浏览器为了判断服务器是否支持跨域请求,会在实际发送GET请求之前,先发送一个OPTIONS请求进行预检查。如果服务器支持跨域请求,浏览器则会继续发送正常的GET请求;如果不支持,则浏览器无法正常发送GET请求‌。

这种预检查机制是浏览器的一种安全策略,旨在确保只有当服务器明确允许跨域请求时,数据才能从其他域传输到当前域。通过这种方式,可以防止恶意站点执行可能危害用户的操作,如读取敏感数据或执行恶意脚本。因此,开发人员在处理跨域请求时,需要确保服务器正确配置以支持这种预检查机制,否则跨域请求将无法成功‌。

Get请求跨域案例

前端这边有一个get请求,在请求的header里面要添加两个自定义的header。

GET http://localhost:8080/api/v1/users
Accept: */*
Content-Type: application/json
Authorization: token:21232f297a57a5a743894a0e4a801fc3
Username: admin

增加了两个自定义字段 Authorization和Username 在请求时,network里面出现了两次请求记录 第一次是一个 OPTION请求 状态码200第二次是我的get请求 状态码 401。

后端已经做了CORS处理,为何还出现这种情况呢。 我们一般在项目里解决跨域问题简单说会采取方案有:

  • 使用ajax直接跨域访问
  • 使用Jsonp

实际使用时,由于Jsonp向Server提交URL的长度限制在8000字符,超过了则被浏览器拒绝,因此不采用

对于第一种方案,后端需要做的工作是接口允许允许跨域请求:

header('Access-Control-Allow-Origin:*');  //支持全域名访问,不安全,部署后需要限制为R.com
header('Access-Control-Allow-Methods:POST,GET,OPTIONS,DELETE'); //支持的http动作
header('Access-Control-Allow-Headers:x-requested-with,content-type');  //响应头 请按照自己需求添加。

在正式跨域的请求前,浏览器会根据需要,发起一个“PreFlight”(也就是Option请求),用来让服务端返回允许的方法(如get、post),被跨域访问的Origin(来源,或者域),还有是否需要Credentials(认证信息) 三种信息。

如果跨域的请求是Simple Request(简单请求 ),则不会触发“PreFlight”。Mozilla对于简单请求的要求是以下三项必须都成立:

  • 只能是Get、Head、Post方法
  • 除了浏览器自己在Http头上加的信息(如Connection、User-Agent),开发者只能加这几个:Accept、Accept-Language、Content-Type
  • Content-Type只能取这几个值: application/x-www-form-urlencoded multipart/form-data text/plain

XHR对象对于HTTP跨域请求有三种:简单请求、Preflighted 请求、Preflighted 认证请求。

简单请求不需要发送OPTIONS嗅探请求,但只能按发送简单的GET、HEAD或POST请求,且不能自定义HTTP Headers。Preflighted 请求和认证请求,XHR会首先发送一个OPTIONS嗅探请求,然后XHR会根据OPTIONS请求返回的Access-Control-*等头信息判断是否有对指定站点的访问权限,并最终决定是否发送实际请求信息。

那么我的get请求呢?

原来,产生 OPTIOINS 请求的原因是:自定义 Headers 头信息导致的。 浏览器会去向 Server 端发送一个 OPTIONS 请求,看 Server 返回的 "Access-Control-Allow-Headers" 是否有自定义的 header 字段。因为我之前没有返回自定义的字段,所以,默认是不允许的,造成了客户端没办法拿到数据。

http post要发起几次请求?

HTTP POST请求通常只需要发起一次请求。‌然而,在特定情况下,如处理复杂请求或跨域请求时,可能会涉及到两次请求。以下是详细解释:

  1. 基本情况‌:在大多数情况下,HTTP POST请求用于向服务器提交数据,这个过程只需要发起一次请求。POST请求的参数放在request body中,可以支持多种编码方式和无限制的字符集,这使得POST请求成为提交大量数据时的理想选择。

  2. 复杂请求处理‌:在处理包含自定义HTTP头部的复杂请求时,例如需要在header中添加token或其他用户信息进行校验,这种情况下可能会先发送一个OPTIONS请求。这是为了检查服务器是否接受跨域请求,以及客户端是否有权限进行跨域访问。如果预检请求(OPTIONS请求)成功,客户端才会发送实际的POST请求。

  3. 跨域请求‌:当发生跨域请求时,浏览器为了保证安全,会首先发送一个OPTIONS请求,即预检请求。这个请求用于检查服务器是否接受来自特定源的请求。如果预检请求成功,浏览器才会发送实际的POST请求进行数据提交。

综上所述,HTTP POST请求在基本情况下只需要发起一次请求,但在处理复杂请求或跨域请求时,可能会涉及到两次请求,即先发送OPTIONS预检请求,然后根据预检请求的结果决定是否发送实际的POST请求‌。

第一次请求:

General

Request Method:OPTIONS

Status Code:204 No Content

Response Headers

Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:access-control-allow-methods,authorization,content-type
Access-Control-Allow-Methods:GET,HEAD,PUT,POST,DELETE,PATCH
Access-Control-Allow-Origin:https://xxxxxxxxx.com
Date:Mon, 18 Dec 2023 09:24:21 GMT
Strict-Transport-Security:max-age=15724800; includeSubDomains
Vary:Origin

作用:

1、复杂请求

请求中有自定义HTTP头部,所谓的自定义头部,在实际的项目里,我们经常会遇到需要在header头部加上一些token或者其他的用户信息,用来做用户信息的校验。

只要是带自定义header的跨域请求,在发送真实请求前都会先发送OPTIONS请求,浏览器根据OPTIONS请求返回的结果来决定是否继续发送真实的请求进行跨域资源访问。所以复杂请求肯定会两次请求服务端。

2、发生了跨域。

在跨域请求中,浏览器为了确保安全,会首先发送一个OPTIONS请求,也被称为预检请求。如果预检请求成功,浏览器才会发出实际的POST请求。

options请求有什么作用:

官方将头部带自定义信息的请求方式称为带预检(preflighted)的跨域请求。在实际调用接口之前,会首先发出一个options请求,检测服务端是否支持真实的请求进行跨域的请求。

16种常用的HTTP状态码

   HTTP状态码一共有60多种,但是不用全部都记住,因为大部分在工作当中是不经常使用的。经常使用的大概就是16种,下面来详细介绍。(其实最最常用的也就8种,下面有背景色的就是)

             1. 200:OK

             这个没有什么好说的,是代表请求被正常的处理成功了。

             2. 204:No Content

             请求处理成功,但是没有数据实体返回,也不允许有实体返回。比如说HEAD请求,可能就会返回204 No Content,因为HEAD就是只获取头信息。这里简单提一下205 Reset Content,和204 No Content的区别是不但没有数据实体返回,而且还需要重置表单,方便用户再次输入。

             3. 206:Partial Content

             这是客户端使用Content-Range指定了需要的实体数据的范围,然后服务端处理请求成功之后返回用户需要的这一部分数据而不是全部,执行的请求就是GET。返回码就是206:Partial Content。

             4. 301 : Moved Permanently

             代表永久性定向。该状态码表示请求的资源已经被分配了新的URL,以后应该使用资源现在指定的URL。也就是说如果已经把资源对应的URL保存为书签了,这是应该按照Location首部字段提示的URL重新保存。

             5. 302:Found

             代表临时重定向。该状态码表示请求的资源已经被分配了新的URL,但是和301的区别是302代表的不是永久性的移动,只是临时的。就是说这个URL还可能会发生改变。如果保存成书签了也不会更新。

             6. 303:See Other

             和302的区别是303明确规定客户端应当使用GET方法。

             7. 304:Not Modified

             该状态码表示客户端发送附带条件请求时,服务器端允许请求访问资源,但是没有满足条件。304状态码返回时不包含任何数据实体。304虽然被划分在3XX中但是和重定向没有关系。

             8. 307:Temporary Redirect

             临时重定向,与302 Found相同,但是302会把POST改成GET,而307就不会。

             9. 400:Bad Request

             400表示请求报文中存在语法错误。需要修改后再次发送。

             10. 401:Unauthorized

             该状态码表示发送的请求需要有通过HTTP认证的认证信息。

             11. 403:Forbidden

             表明请求访问的资源被拒绝了。没有获得服务器的访问权限,IP被禁止等。

             12. 404:Not Found

             表明请求的资源在服务器上找不到。当然也可以在服务器拒绝请求且不想说明理由时使用。

             13. 408:Request Timeout

             表示客户端请求超时,就是在客户端和服务器建立连接后服务器在一定时间内没有收到客户端的请求。

             14. 500:Internal Server Error

             表明服务器端在执行请求时发生了错误,很有可能是服务端程序的Bug或者临时故障。

             15. 503:Service Unavailable

             表明服务器暂时处于超负载或正在进行停机维护,现在无法处理请求。如果事先得知解除以上状况需要的时间,最好写入Retry-After字段再返回给客户端。

             16. 504:Getaway Timeout

             网关超时,是代理服务器等待应用服务器响应时的超时,和408 Request Timeout的却别就是504是服务器的原因而不是客户端的原因

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

-无-为-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值