PATCH 方法和 CORS 预检请求存在问题
Posted
技术标签:
【中文标题】PATCH 方法和 CORS 预检请求存在问题【英文标题】:Problem with PATCH method and CORS preflight request 【发布时间】:2019-08-10 12:42:03 【问题描述】:我正在开发的应用程序有问题。 API 使用 php Symfony 4,应用程序使用 Ionic 4。
我在执行 PATCH 请求时遇到问题。该请求在 POSTMAN 以及我的手机上运行良好 但是在尝试使用浏览器(Google Chrome、Firefox)时,我遇到了 CORS 问题。
我已经询问并且我了解 PATCH 请求首先通过飞行前请求,因此发送请求 使用我的 API 的 OPTIONS 方法。
我管理了这个方法并返回了一个代码 200 然后我在我的 index.php 文件中允许了正确的标题,如下所示:
header('Access-Control-Allow-Origin: *');
header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept");
header("Access-Control-Allow-Methods: GET, HEAD, PATCH, OPTIONS, POST, PUT");
一开始,我遇到了第一个错误,表明请求没有返回代码 200,所以我在我的 API 中管理了 OPTIONS 方法。 然后我有以下错误:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
这很奇怪,因为之前没有出现错误,并且所有其他请求都有效。
此外,我尝试使用 POSTMAN 并且 OPTIONS 方法返回正确的标题。
你能帮帮我吗?
对不起,英语粗鲁。
【问题讨论】:
您是否也在实际请求中添加了标头?据我所知,您不必支持所有 http 方法。 我应该在哪个查询上添加标题?在前面? 应该在所有允许跨域的请求上添加 cors-headers。不仅仅是头部或选项。 是的,我将它们添加到我的 Symfony 项目根目录下的 index.php 文件中 请求的资源(您应该看到访问了哪个资源)是否是静态文件(位于 public/web 文件夹或子文件夹中)?因为这些通常是直接交付的,没有被 index.php 转发(但你可以强制这样的事情......) 【参考方案1】:对于将来发现此问题的任何人,我已经重现了这些确切的症状,并解决了我的问题。简短的回答是,当在客户端指定方法时(例如在fetch
选项中),PATCH
特别区分大小写,而其他方法则不区分。需要大写。
根据我所能推断的最好的解释是,即使RFC7230 声明方法应该是大写的,它们也是区分大小写的。浏览器通过自动大写其中几个来平滑这一点,我相信基于RFC7231,它定义了许多常用方法,但没有定义 PATCH。考虑以下从客户端发起的请求。
fetch('https://***.com',
method: 'post',
body: JSON.stringify(message: 'testing a cors issue'),
headers: 'Content-Type': 'application/json'
)
至少对于 Chromium 浏览器而言,正常行为是自动将 CORS 预检的 Access-Control-Request-Method
标头中的方法大写,而不管我的 javascript 在 fetch 调用中使用的大小写。
同样,如果方法是DELETE
,浏览器也会在预检中自动大写。
但是,我发现PATCH
方法(稍后在RFC5789 中定义)被视为自定义HTTP 方法,因为它没有被强制大写。因此它是区分大小写的,这在 CORS 预检期间可以观察到。如果客户端应用程序以小写 patch
指定它,则它在 Access-Control-Request-Method 标头中显示,如果它是大写的 PATCH
,它在标头中显示为大写。
当您在 Postman 中选择 PATCH
方法时,它总是大写,这掩盖了问题的根本原因。尽管错误消息与 Access-Control-Allow-Origin
标头有关,但我看到的根本原因是该方法区分大小写。
【讨论】:
正确,根据 HTTP 规范——以及所有其他 RFC——all HTTP 方法是区分大小写的。另见***.com/a/27427356/441757。因此,根据 HTTP 和其他 RFC,patch
和 PATCH 是不同的方法 - 而get
与 GET 等也是不同的方法。因此,为了严格遵守 HTTP/RFC 要求,HTTP 服务器和 HTTP 客户端都不能将 patch
方法视为真正的 PATCH,或将 get
等方法视为 GET 等. 所以这就是大多数 HTTP 服务器实际上所做的。但 HTTP 客户端在实践中所做的是另一回事。
浏览器实际上违反了 HTTP 规范对方法不区分大小写的要求。见github.com/whatwg/fetch/issues/50#issuecomment-188241506。但是他们以标准方式违反了它,定义在fetch.spec.whatwg.org/#concept-method-normalize,它说,“为了规范化一个方法,如果它是一个不区分大小写的 DELETE、GET、HEAD、OPTIONS、POST 或 PUT 匹配, 字节大写。” 因此,由于 PATCH 不在该列表中,因此浏览器从不大写 patch
— 也没有任何其他方法,除了该列表中的方法。浏览器为列出的浏览器这样做的唯一原因是向后兼容性。
@sideshowbarker 这是很好的背景信息。很好的补充。【参考方案2】:
Environement info-
ionic (Ionic CLI) : 4.0.0
Ionic Framework : @ionic/angular 4.0.0
@angular-devkit/build-angular : 0.8.6
@angular-devkit/schematics : 0.8.6
@angular/cli : 6.2.6
@ionic/angular-toolkit : 1.1.0
要修复 CORS 错误,您应该按照以下步骤操作:
-
创建 到您的 Ionic 项目(在根目录中)一个文件调用它:
proxy.conf.json
在里面写这个(复制/粘贴):
"/api/*": "target": "http://myremoteserver/api", "secure": false, "logLevel": "debug"
打开您的angular.json
文件并将proxyConfig":
"proxy.conf.json"
行设置为"serve":
"serve":
"builder": "@angular-devkit/build-angular:dev-server",
"options":
"browserTarget": "app:build",
proxyConfig": "proxy.conf.json"
,
"configurations":
"production":
"browserTarget": "app:build:production"
打开您的package.json
并将这一行添加到脚本
数组:
"start": "ng serve --port 8100 --proxy-config proxy.conf.json"
你应该得到这样的东西(见下文):
"scripts":
"ng": "ng",
"start": "ng serve --port 8100 --proxy-config proxy.conf.json",
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
在命令行中运行此命令后:npm run start
如果您按照这些步骤操作应该是OK
就我而言,它正在工作!!!
最好的问候
【讨论】:
以上是关于PATCH 方法和 CORS 预检请求存在问题的主要内容,如果未能解决你的问题,请参考以下文章
Angular $http.delete CORS 错误(预检请求)