序言-引出问题
本人在毕业之后主要是从事游戏开发的客户端相关工作,由于游戏引擎的跨平台功能,所以在游戏开发完成之后,需要发布的平台经常会包含Web平台(包括desktop Web、Mobile Web)。
打包出来的项目文件的入口都是index.html文件。
但是如果直接双击打开index.html之后,在浏览器上是运行不起来的,都会报以下类似的错误
其中,主要关注这个错误:
from origin 'null' has been blocked by CORS policy
这个错误引发两个关键点。
origin 'null'
CORS policy
这里首先要解释“CORS”,再解释“origin ''null'”。
CORS
先来个官方解释:
CORS(Cross-Origin Resource Sharing,跨源资源共享)是一种安全机制,防止非同源的域进行数据交互。出现这个错误通常意味着你的前端应用尝试从一个与其自身不同源的域(origin)获取资源,但该域没有明确地给予允许。
好的,又是一长串用概念拼接起来的文字,读起来费劲。
那么我们再来找重点——非(不)同源的域(origin)。
为什么需要有CORS
在接触一项我们之前没有了解的技术的时候,我们都应该有一个习惯,那就是问一下为什么会需要这个技术。
在CORS的解释中,已经说出CORS是为了防止非同源的域进行数据交互,是一种安全机制。
那么了解为什么会有CORS,就要了解在没有CORS之前,怎么处理跨域问题。
在没有CORS之前,主要是使用JSONP来解决跨域的问题。
那么我们先来了解JSONP大概是怎么样的:
- JSONP是一种利用
<script>
标签进行跨域请求的技术,不是一种数据格式。- JSONP主要用于解决浏览器同源策略限制下的跨域问题,允许从不同域的服务器获取数据。
- JSONP通过在URL中指定一个回调函数名(padding),服务器在响应时将数据包裹在该函数的调用中返回,从而使得浏览器能够执行该回调函数并获取数据。
- 示例: 如果请求的URL为
http://example.com/data?callback=myCallback
,服务器返回的响应可能是myCallback({"name": "John", "age": 30})
,浏览器会执行myCallback
函数,并传入数据作为参数。
其实我对JSONP也不是很了解,以上的内容主要来自网站搜索(如果大家对为什么有JSONP还感兴趣的话,可以自行查阅相关资料)。
那么为什么CORS可以替代JSONP才处理跨域的问题,CORS对比JSONP,有什么优点。
安全性高:CORS 是浏览器提供的一种机制,通过设置 HTTP 头部来允许跨源请求。它的设计目标是保护用户的安全,避免恶意网站利用跨域请求进行攻击。
支持多种 HTTP 方法:CORS 支持所有类型的 HTTP 请求,包括 GET、POST、PUT、DELETE 等,因此更加灵活。
支持多种数据格式:CORS 不仅支持 JSON 数据,还支持其他类型的资源和数据格式,如 XML、HTML 等。
规范化:CORS 是 W3C 标准的一部分,得到了广泛的支持和推广,成为了现代 Web 应用开发中处理跨域问题的首选解决方案。
其中主要注意支持多种HTTP方法。所以现代 Web 应用程序中,特别是使用 Ajax 请求和 API 访问时,推荐使用 CORS。它安全、灵活,并且符合现代 Web 标准。
怎么才算不同源(跨域)
所谓不同源,就引出了在Web的开发中,一个经常出现的词,那就是“跨域”。
那么这个域怎么才算同源,怎么才算不同源。
是否同源由CORS的同源策略决定。CORS的同源策略:
同源策略的判断规则:
协议(Protocol):
- 两个 URL 的协议部分必须完全相同(例如都是
http
或者都是https
)。域名(Host):
- 两个 URL 的主机名部分(域名部分)必须完全相同(例如
www.example.com
和api.example.com
不同源)。端口(Port):
- 如果 URL 包含端口号,则两个 URL 的端口号必须完全相同(例如
http://example.com:80
和http://example.com:8080
不同源)。- 如果 URL 没有明确指定端口号,默认端口号为
80
(http
)和443
(https
)。
只要其中一个同源条件不符合,那么就判定为跨域(即不同源)。
origin 'null'
再来说说这个词的意思,origin 'null'可能表示请求的来源是非明确的或未知的,这可能是因为请求没有正确地设置Origin头部,或者是因为请求是从本地文件系统(file://)发起的。
所以这个解释就符合我们前面双击打开文件这个操作。
如何解决
解决web页面部署跨域的方法可以分为两类,一、需要前端来解决;二、服务器来解决。
前端来解决
由前端来解决的问题类型
有以下几种问题是由前端来解决的:
System.import
System.import
(或import()
,ES6 动态导入)这个接口,和其他的 JavaScript 接口和情况也会触发 CORS(跨源资源共享)问题。动态脚本加载跨域问题:
- 动态创建
<script>
标签加载跨域脚本时,同样受到浏览器的同源策略限制。可以考虑使用 JSONP 或 CORS 解决方案。AJAX 请求跨域问题:
- 使用 XMLHttpRequest 或 Fetch API 发起跨域请求时,需要处理浏览器的同源策略限制。解决方法包括使用 CORS、JSONP、代理服务器等。
Cookies 跨域问题:
- 默认情况下,浏览器不会发送跨域请求的 Cookie。如果需要在跨域请求中发送和接收 Cookie,需要在服务器端设置
Access-Control-Allow-Credentials
为true
,并在客户端设置withCredentials
为true
。LocalStorage 和 IndexedDB 跨域问题:
- 虽然这些本地存储机制通常不直接受到 CORS 的影响,但如果跨域请求获取数据并存储在本地存储中,可能需要考虑安全性和数据隔离的问题。
前端框架或库中的跨域支持:
- 一些前端框架或库可能会提供跨域请求的封装或支持,开发人员需要了解和使用这些功能来简化跨域请求的处理。
其中经常出现的是前三种情况 ,在文章开头的问题就是第二种动态脚本加载跨域问题。
那么如何解决前端如何解决以上类型的问题呢?主要有以下两种方式:
使用代理服务器:
- 如果直接在客户端无法修改请求或处理CORS问题,可以考虑在客户端和服务端之间部署代理服务器。代理服务器可以在服务器端发送请求,然后将响应返回给客户端,避免跨域限制。
使用JSONP:
- 对于仅支持 GET 请求的跨域数据获取,可以考虑使用 JSONP。JSONP 利用
<script>
标签没有跨域限制的特性,通过动态创建<script>
标签来加载数据。
其中使用代理服务器是最为常见的解决方案,代理服务器又分为正向代理服务器、反向代理服务器、Web服务器等。
其中反向代理服务器又是最为常见的代理服务器,而反向代理服务器又有Nginx、Apache等。
其中Nginx又是最为常见的反向代理服务器,所以我们需要把我们的html页面及所有资源都部署到Nginx的服务器上面去。
Nginx如何解决CORS
Nginx的概念
Nginx同Apache一样都是一种Web 服务器、反向代理服务器,也可以用作负载均衡器和 HTTP 缓存。
Nginx基于REST架构风格,以统一资源描述符(Uniform Resources Identifier)URI 或者 统一资源定位符(Uniform Resources Locator)URL 作为沟通依据,通过 HTTP 协议提供各种网络服务。
由于它的内存占用少,启动极快,高并发能力强,在互联网项目中广泛应用。
Nginx解决CORS的方法
Nginx可以解决CORS(跨源资源共享)问题,主要是因为它作为反向代理服务器,具有灵活的配置能力和强大的请求处理功能。以下是几个关键原因:
添加HTTP响应头: Nginx可以通过配置文件中的
add_header
指令,动态地添加HTTP响应头。对于CORS来说,主要是通过添加Access-Control-Allow-Origin
、Access-Control-Allow-Methods
、Access-Control-Allow-Headers
等头部来告知浏览器哪些源、方法和头部是允许的。这使得Nginx能够在代理请求时向响应中注入必要的CORS头部信息。处理预检请求(OPTIONS请求): 跨源请求中,浏览器在发送一些特殊类型的请求(如带有自定义头部的请求或非简单请求)之前,会发送一个预检请求(OPTIONS请求)。Nginx能够通过配置在收到这类请求时,正确响应预检请求,包括返回允许的方法、头部等信息,从而使浏览器在正式发送实际请求前获得必要的确认。
灵活的位置和服务器块配置: Nginx的配置文件允许在不同的位置块(
location
block)或服务器块(server
block)中针对不同的URL路径或虚拟主机配置CORS。这种灵活性使得可以根据需要细粒度地控制CORS策略,以满足不同的业务需求和安全要求。性能和可扩展性: Nginx因其高性能和低资源消耗而广受欢迎,能够处理大量并发请求。通过在Nginx层面解决CORS问题,可以减少后端服务器的负担,提高整体系统的性能和可扩展性。
综上所述,Nginx作为反向代理服务器,具备处理HTTP请求和响应的强大功能,使其能够有效地解决CORS问题。通过正确配置CORS相关的HTTP头部和处理预检请求,Nginx能够帮助应用程序和服务在跨源请求中实现安全、可靠的数据交换。
Tips:关于Nginx的更多内容,请自行查询。
服务器来解决
由服务器来解决的问题来源
在正常的Web页面开发流程中,有两个概念比较重要,第一是Web页面的资源地址,第二是Web页面请求接口的服务器地址。
Web页面的资源链接地址往往与Web页面请求接口的服务器地址不一致。
这就是造成这一类CORS问题的主要来源。
服务器解决CORS问题主要方法
服务器通过以下方法来处理CORS(在Go、Java、NodeJs都适用)。
第一、设置Access-Control-Allow-Origin
头部:
- 这是最基本的CORS响应头部。通过设置
Access-Control-Allow-Origin
头部,可以指定允许访问资源的域名或使用通配符*
表示允许所有域名访问。例如,允许所有域名访问可以这样设置:
Access-Control-Allow-Origin: *
或者指定具体的域名:
Access-Control-Allow-Origin: https://example.com
第二、处理预检请求(OPTIONS请求):
- 对于某些复杂请求(例如带有自定义头部或使用非简单 HTTP 方法的请求),浏览器会先发送一个 OPTIONS 请求(预检请求)。服务器需要正确响应这个预检请求,包括返回适当的CORS头部和响应状态码(如200 OK)。
- 设置
Access-Control-Allow-Methods
头部指定允许的 HTTP 方法,如GET
,POST
,PUT
,DELETE
等。 - 设置
Access-Control-Allow-Headers
头部指定允许的 HTTP 头部,例如Content-Type
,Authorization
等。
第三、允许发送 Cookie 和 HTTP 认证信息:
- 如果跨域请求需要发送和接收 Cookie 或 HTTP 认证信息,服务器需要设置
Access-Control-Allow-Credentials: true
头部,并在客户端请求中设置credentials: 'include'
。