HTTP 第六章 跨资源共享(CORS)

2024-02-22 09:12

本文主要是介绍HTTP 第六章 跨资源共享(CORS),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

跨资源共享(CORS)

跨源资源共享(CORS,或通俗地译为跨域资源共享)是一种基于 HTTP 头的机制,该机制通过允许服务器标示除了它自己以外的其他源(域、协议或端口),使得浏览器允许这些源访问加载自己的资源。跨源资源共享还通过一种机制来检查服务器是否会允许要发送的真实请求,该机制通过浏览器发起一个到服务器托管的跨源资源的“预检”请求。在预检中,浏览器发送的头中标示有 HTTP 方法和真实请求中会用到的头。

例如:运行在 https://baidu.com 的js代码使用 XMLHttpRequest 向 https://google.com 发起请求。

出于安全性,浏览器限制脚本内发起的跨源 HTTP 请求。这意味着使用这些 API 的 Web 应用程序只能从加载应用程序的同一个域请求 HTTP 资源,除非响应报文包含了正确 CORS 响应头。

CORS 机制允许 Web 应用服务器进行跨源访问控制,从而使跨源数据传输得以安全进行。

CORS 规范要求

对可能对服务器数据产生副作用的 HTTP 请求方法(特别是 GET 以外的 HTTP 请求,或者搭配某些 MIME 类型的 POST 请求),浏览器必须首先使用 OPTIONS 方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨源请求。

服务器确认允许之后,才发起实际的 HTTP 请求。

在预检请求的返回中,服务器端也可以通知客户端,是否需要携带身份凭证(例如 Cookie 和 HTTP 认证相关数据)

跨域请求的分类

简单请求

简单请求不会触发 CORS 预检请求。

如果请求满足所有下述条件,则该请求可视为简单请求:

  • 请求方法是以下三种方法之一:
    • HEAD
    • GET
    • POST
  • 除了被用户代理自动设置的标头字段(例如 Connection、User-Agent 或其他在 Fetch 规范中定义为禁用标头名称的标头),允许人为设置的字段为 Fetch 规范定义的对 CORS 安全的标头字段集合。该集合为:
    • Accept
    • Accept-Language
    • Content-Language
    • Content-Type 所制定的请求头仅限于下列三者
      • application/x-www-form-urlencoded
      • multipart/form-data
      • text/plain
    • Range (只允许简单的范围标头值 如 bytes=256- 或 bytes=127-255)
    • 如果请求是使用 XMLHttpRequest 对象发出的,在返回的 XMLHttpRequest.upload 对象属性上没有注册任何事件监听器;也就是说,给定一个 XMLHttpRequest 实例 xhr,没有调用 xhr.upload.addEventListener(),以监听该上传请求。
    • 请求中没有使用 ReadableStream 对象

例如: 站点 https://foo.example 网页应用想要访问 https://bar.other 的资源

fetch('https://bar.other/test', {method: 'GET',
}).then(res => res.json()).then(res => console.log(res));

此操作实行了客户端和服务器之间的简单交换,使用 CORS 标头字段来处理权限:

服务端返回的 Access-Control-Allow-Origin 标头的 Access-Control-Allow-Origin: * 值表明,该资源可以被任意外源访问

const express = require('express');const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: false }));app.get('/test', (req, res) => {res.header('Access-Control-Allow-Origin', '*');res.send({code: 0,data: 'hello world'});
});app.listen(3000, () => {console.log('server is running on port 3000');
});

如果 https://bar.other 的资源持有者想限制他的资源只能通过 https://foo.example 来访问,可以这样做:Access-Control-Allow-Origin: https://foo.example

预检请求

当不满足简单请求的条件时,浏览器会发送预检请求“需预检的请求”要求必须首先使用 OPTIONS 方法发起一个预检请求到服务器,以获知服务器是否允许该实际请求。
"预检请求“ 的使用,可以避免跨域请求对服务器的用户数据产生未预期的影响。

如下是一个需要执行预检请求的 HTTP 请求:

fetch('https://bar.other/test', {method: 'POST',headers: {'X-PINGOTHER': 'pingpong','Content-Type': 'application/xml',}
}).then(res => res.json()).then(res => console.log(res));

上面的代码发送 POST 请求,该请求包含了一个非标准的 HTTP X-PINGOTHER 请求标头。这样的请求标头并不是 HTTP/1.1 的一部分,但通常对于 web 应用很有用处。另外,该请求的 Content-Type 为 application/xml,且使用了自定义的请求标头,所以该请求需要首先发起“预检请求”。

下面是服务端和客户端完整的信息交互。

首次交互是预检请求/响应
浏览器根据上面的 JavaScript 代码片断所使用的请求参数,向服务端发送一个预检请求,该请求的请求头如下:

OPTIONS /doc HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Connection: keep-alive
Origin: https://foo.example
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER, Content-Type

标头字段 Access-Control-Request-Method 告知服务器,实际请求将使用 POST 方法。
标头字段 Access-Control-Request-Headers 告知服务器,实际请求将携带两个自定义请求标头字段:X-PINGOTHER 与 Content-Type。

服务器根据预检请求的请求头信息,决定是否允许该实际请求。

HTTP/1.1 204 No Content
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2
Access-Control-Allow-Origin: https://foo.example
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
Access-Control-Max-Age: 86400
Vary: Accept-Encoding, Origin
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive

对于预检请求,不需要响应任何的消息体,只需要在响应头中添加:

  • Access-Control-Allow-Origin:和简单请求一样,表示允许的源
  • Access-Control-Allow-Methods:表示允许的后续真实的请求方法
  • Access-Control-Allow-Headers:表示允许改动的请求头
  • Access-Control-Max-Age:告诉浏览器,多少秒内,对于同样的请求源、方法、头,都不需要再发送预检请求了

预检请求完成之后,发送实际请求

附带身份凭证的请求

XMLHttpRequest 或 Fetch,可以基于 HTTP cookies 和 HTTP 认证信息发送身份凭证。默认情况下,跨域请求并不会附带cookie。以通过简单的配置就可以实现附带cookie。

// xhr
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;// fetch api
fetch(url, {credentials: "include"
})

当一个请求需要附带cookie时,无论它是简单请求,还是预检请求,都会在请求头中添加cookie字段。
服务器响应时,需要明确告知客户端:服务器允许这样的凭据。需要在响应头中添加:Access-Control-Allow-Credentials: true

在响应附带身份凭证的请求时:

  1. 服务器不能将 Access-Control-Allow-Origin 的值设为通配符“*”,而应将其设置为特定的域,如:Access-Control-Allow-Origin: https://example.com。
  2. 服务器不能将 Access-Control-Allow-Headers 的值设为通配符“*”,而应将其设置为标头名称的列表,如:Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
  3. 服务器不能将 Access-Control-Allow-Methods 的值设为通配符“*”,而应将其设置为特定请求方法名称的列表,如:Access-Control-Allow-Methods: POST, GET

在跨源访问时,浏览器只能拿到一些最基本的响应头,Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma,如果要访问其他头,则需要服务器设置本响应头。

Access-Control-Expose-Headers头让服务器把允许浏览器访问的头放入白名单,例如:

Access-Control-Expose-Headers: X-My-Custom-Header, X-Another-Custom-Header

这样JS就能够访问指定的响应头了。

这篇关于HTTP 第六章 跨资源共享(CORS)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/734786

相关文章

Node.js 中 http 模块的深度剖析与实战应用小结

《Node.js中http模块的深度剖析与实战应用小结》本文详细介绍了Node.js中的http模块,从创建HTTP服务器、处理请求与响应,到获取请求参数,每个环节都通过代码示例进行解析,旨在帮... 目录Node.js 中 http 模块的深度剖析与实战应用一、引言二、创建 HTTP 服务器:基石搭建(一

Python如何实现 HTTP echo 服务器

《Python如何实现HTTPecho服务器》本文介绍了如何使用Python实现一个简单的HTTPecho服务器,该服务器支持GET和POST请求,并返回JSON格式的响应,GET请求返回请求路... 一个用来做测试的简单的 HTTP echo 服务器。from http.server import HT

BUUCTF靶场[web][极客大挑战 2019]Http、[HCTF 2018]admin

目录   [web][极客大挑战 2019]Http 考点:Referer协议、UA协议、X-Forwarded-For协议 [web][HCTF 2018]admin 考点:弱密码字典爆破 四种方法:   [web][极客大挑战 2019]Http 考点:Referer协议、UA协议、X-Forwarded-For协议 访问环境 老规矩,我们先查看源代码

【Linux】应用层http协议

一、HTTP协议 1.1 简要介绍一下HTTP        我们在网络的应用层中可以自己定义协议,但是,已经有大佬定义了一些现成的,非常好用的应用层协议,供我们直接使用,HTTP(超文本传输协议)就是其中之一。        在互联网世界中,HTTP(超文本传输协议)是一个至关重要的协议,他定义了客户端(如浏览器)与服务器之间如何进行通信,以交换或者传输超文本(比如HTML文档)。

如何确定 Go 语言中 HTTP 连接池的最佳参数?

确定 Go 语言中 HTTP 连接池的最佳参数可以通过以下几种方式: 一、分析应用场景和需求 并发请求量: 确定应用程序在特定时间段内可能同时发起的 HTTP 请求数量。如果并发请求量很高,需要设置较大的连接池参数以满足需求。例如,对于一个高并发的 Web 服务,可能同时有数百个请求在处理,此时需要较大的连接池大小。可以通过压力测试工具模拟高并发场景,观察系统在不同并发请求下的性能表现,从而

Anaconda 中遇到CondaHTTPError: HTTP 404 NOT FOUND for url的问题及解决办法

最近在跑一个开源项目遇到了以下问题,查了很多资料都大(抄)同(来)小(抄)异(去)的,解决不了根本问题,费了很大的劲终于得以解决,记录如下: 1、问题及过程: (myenv) D:\Workspace\python\XXXXX>conda install python=3.6.13 Solving environment: done.....Proceed ([y]/n)? yDownloa

构建高性能WEB之HTTP首部优化

0x00 前言 在讨论浏览器优化之前,首先我们先分析下从客户端发起一个HTTP请求到用户接收到响应之间,都发生了什么?知己知彼,才能百战不殆。这也是作为一个WEB开发者,为什么一定要深入学习TCP/IP等网络知识。 0x01 到底发生什么了? 当用户发起一个HTTP请求时,首先客户端将与服务端之间建立TCP连接,成功建立连接后,服务端将对请求进行处理,并对客户端做出响应,响应内容一般包括响应

Golang支持平滑升级的HTTP服务

前段时间用Golang在做一个HTTP的接口,因编译型语言的特性,修改了代码需要重新编译可执行文件,关闭正在运行的老程序,并启动新程序。对于访问量较大的面向用户的产品,关闭、重启的过程中势必会出现无法访问的情况,从而影响用户体验。 使用Golang的系统包开发HTTP服务,是无法支持平滑升级(优雅重启)的,本文将探讨如何解决该问题。 一、平滑升级(优雅重启)的一般思路 一般情况下,要实现平滑

Java http请求示例

使用HttpURLConnection public static String httpGet(String host) {HttpURLConnection connection = null;try {URL url = new URL(host);connection = (HttpURLConnection) url.openConnection();connection.setReq

3.比 HTTP 更安全的 HTTPS(工作原理理解、非对称加密理解、证书理解)

所谓的协议 协议只是一种规则,你不按规则来就无法和目标方进行你的工作 协议说白了只是人定的规则,任何人都可以定协议 我们不需要太了解细节,这些制定和完善协议的人去做的,我们只需要知道协议的一个大概 HTTPS 协议 1、概述 HTTPS(Hypertext Transfer Protocol Secure)是一种安全的超文本传输协议,主要用于在客户端和服务器之间安全地传输数据