HTTP access control (CORS)
Redirected from HTTP access control (CORS) Redirect 1
Table of Contents
- Files
Cross-site HTTP requests are HTTP requests for resources from a different domain than the domain of the resource making the request. For instance, a resource loaded from Domain A (http://domaina.example) such as an HTML web page, makes a request for a resource on Domain B (http://domainb.foo), such as an image, using the img
element (http://domainb.foo/image.jpg). This occurs very commonly on the web today — pages load a number of resources in a cross-site manner, including CSS stylesheets, images and scripts, and other resources.
Cross-site HTTP requests initiated from within scripts have been subject to well-known restrictions, for well-understood security reasons. For example HTTP Requests made using the XMLHttpRequest
object were subject to the same-origin policy. In particular, this meant that a web application using XMLHttpRequest
could only make HTTP requests to the domain it was loaded from, and not to other domains. Developers expressed the desire to safely evolve capabilities such as XMLHttpRequest
to make cross-site requests, for better, safer mash-ups within web applications.
The Web Applications Working Group within the W3C has proposed the new Cross-Origin Resource Sharing (CORS) recommendation, which provides a way for web servers to support cross-site access controls, which enable secure cross-site data transfers. Of particular note is that this specification is used within an API container such as XMLHttpRequest
as a mitigation mechanism, allowing the crossing of the same-domain restriction in modern browsers. The information in this article is of interest to web administrators, server developers and web developers. Another article for server programmers discussing cross-origin sharing from a server perspective (with PHP code snippets) is supplementary reading. On the client, the browser handles the components of cross-origin sharing, including headers and policy enforcement. The introduction of this new capability, however, does mean that servers have to handle new headers, and send resources back with new headers.
This cross-origin sharing standard is used to enable cross-site HTTP requests for:
- Invocations of the
XMLHttpRequest
API in a cross-site manner, as discussed above. - Web Fonts (for cross-domain font usage in
@font-face
within CSS), so that servers can deploy TrueType fonts that can only be cross-site loaded and used by web sites that are permitted to do so. - WebGL textures.
- Images drawn to a canvas using drawImage.
This article is a general discussion of Cross-Origin Resource Sharing, and includes a discussion of the HTTP headers as implemented in Firefox 3.5.
Overview
The Cross-Origin Resource Sharing standard works by adding new HTTP headers that allow servers to describe the set of origins that are permitted to read that information using a web browser. Additionally, for HTTP request methods that can cause side-effects on user data (in particular, for HTTP methods other than GET
, or for POST
usage with certain MIME types), the specification mandates that browsers "preflight" the request, soliciting supported methods from the server with an HTTP OPTIONS
request header, and then, upon "approval" from the server, sending the actual request with the actual HTTP request method. Servers can also notify clients whether "credentials" (including Cookies and HTTP Authentication data) should be sent with requests.
Subsequent sections discuss scenarios, as well as a breakdown of the HTTP headers used.
Examples of access control scenarios
Here, we present three scenarios that are illustrative of how Cross-Origin Resource Sharing works. All of these examples use the XMLHttpRequest
object, which can be used to make cross-site invocations in any supporting browser.
The JavaScript snippets included in these sections (and running instances of the server-code that correctly handles these cross-site requests) can be found "in action" here, and will work in browsers that support cross-site XMLHttpRequest
. A discussion of Cross-Origin Resource Sharing from a server perspective (including PHP code snippets) can be found here.
Simple requests
A simple cross-site request is one that:
- Only uses GET or POST. If POST is used to send data to the server, the Content-Type of the data sent to the server with the HTTP POST request is one of
application/x-www-form-urlencoded
,multipart/form-data
, ortext/plain.
- Does not set custom headers with the HTTP Request (such as
X-Modified
, etc.)
For example, suppose web content on domain http://foo.example
wishes to invoke content on domain http://bar.other
. Code of this sort might be used within JavaScript deployed on foo.example:
1
2
3
4
5
6
7
8
9
10
|
var invocation = new XMLHttpRequest();
var url = 'http://bar.other/resources/public-data/' ;
function callOtherDomain() {
if (invocation) {
invocation.open( 'GET' , url, true );
invocation.onreadystatechange = handler;
invocation.send();
}
} |
Let us look at what the browser will send the server in this case, and let's see how the server responds:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
GET /resources/public-data/ HTTP /1 .1
Host: bar.other User-Agent: Mozilla /5 .0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko /20081130 Minefield /3 .1b3pre
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
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Connection: keep-alive Referer: http: //foo .example /examples/access-control/simpleXSInvocation .html
Origin: http: //foo .example
HTTP /1 .1 200 OK
Date: Mon, 01 Dec 2008 00:23:53 GMT Server: Apache /2 .0.61
Access-Control-Allow-Origin: * Keep-Alive: timeout=2, max=100 Connection: Keep-Alive Transfer-Encoding: chunked Content-Type: application /xml
[XML Data] |
Lines 1 - 10 are headers sent by Firefox 3.5. Note that the main HTTP request header of note here is the Origin:
header on line 10 above, which shows that the invocation is coming from content on the the domain http://foo.example
.
Lines 13 - 22 show the HTTP response from the server on domain http://bar.other
. In response, the server sends back an Access-Control-Allow-Origin:
header, shown above in line 16. The use of the Origin:
header and of Access-Control-Allow-Origin:
show the access control protocol in its simplest use. In this case, the server responds with a Access-Control-Allow-Origin: *
which means that the resource can be accessed by any domain in a cross-site manner. If the resource owners at http://bar.other
wished to restrict access to the resource to be only from http://foo.example
, they would send back:
Access-Control-Allow-Origin: http://foo.example
Note that now, no other domain other than http://foo.example
(identified by the ORIGIN: header in the request, as in line 10 above) can access the resource in a cross-site manner. The Access-Control-Allow-Origin
header should contain the value that was sent in the request's Origin
header.
Preflighted requests
Unlike simple requests (discussed above), "preflighted" requests first send an HTTP OPTIONS
request header to the resource on the other domain, in order to determine whether the actual request is safe to send. Cross-site requests are preflighted like this since they may have implications to user data. In particular, a request is preflighted if:
- It uses methods other than
GET
orPOST
. Also, ifPOST
is used to send request data with a Content-Type other thanapplication/x-www-form-urlencoded
,multipart/form-data
, ortext/plain
, e.g. if thePOST
request sends an XML payload to the server usingapplication/xml
ortext/xml
, then the request is preflighted. - It sets custom headers in the request (e.g. the request uses a header such as
X-PINGOTHER
)
Starting in Gecko 2.0 (Firefox 4 / Thunderbird 3.3 / SeaMonkey 2.1), the text/plain
, application/x-www-form-urlencoded
, and multipart/form-data
data encodings can all be sent cross-site without preflighting. Previously, only text/plain
could be sent without preflighting.
An example of this kind of invocation might be:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
var invocation = new XMLHttpRequest();
var url = 'http://bar.other/resources/post-here/' ;
var body = '<?xml version="1.0"?><person><name>Arun</name></person>' ;
function callOtherDomain(){
if (invocation)
{
invocation.open( 'POST' , url, true );
invocation.setRequestHeader( 'X-PINGOTHER' , 'pingpong' );
invocation.setRequestHeader( 'Content-Type' , 'application/xml' );
invocation.onreadystatechange = handler;
invocation.send(body);
}
...... |
In the example above, line 3 creates an XML body to send with the POST
request in line 8. Also, on line 9, a "customized" (non-standard) HTTP request header is set (X-PINGOTHER: pingpong
). Such headers are not part of the HTTP/1.1 protocol, but are generally useful to web applications. Since the request (POST
) uses a Content-Type of application/xml
, and since a custom header is set, this request is preflighted.
Let's take a look at the full exchange between client and server:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
OPTIONS /resources/post-here/ HTTP /1 .1
Host: bar.other User-Agent: Mozilla /5 .0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko /20081130 Minefield /3 .1b3pre
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
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Connection: keep-alive Origin: http: //foo .example
Access-Control-Request-Method: POST Access-Control-Request-Headers: X-PINGOTHER HTTP /1 .1 200 OK
Date: Mon, 01 Dec 2008 01:15:39 GMT Server: Apache /2 .0.61 (Unix)
Access-Control-Allow-Origin: http: //foo .example
Access-Control-Allow-Methods: POST, GET, OPTIONS Access-Control-Allow-Headers: X-PINGOTHER Access-Control-Max-Age: 1728000 Vary: Accept-Encoding Content-Encoding: gzip
Content-Length: 0 Keep-Alive: timeout=2, max=100 Connection: Keep-Alive Content-Type: text /plain
POST /resources/post-here/ HTTP /1 .1
Host: bar.other User-Agent: Mozilla /5 .0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko /20081130 Minefield /3 .1b3pre
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
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Connection: keep-alive X-PINGOTHER: pingpong Content-Type: text /xml ; charset=UTF-8
Referer: http: //foo .example /examples/preflightInvocation .html
Content-Length: 55 Origin: http: //foo .example
Pragma: no-cache Cache-Control: no-cache <?xml version= "1.0" ?><person><name>Arun< /name >< /person >
HTTP /1 .1 200 OK
Date: Mon, 01 Dec 2008 01:15:40 GMT Server: Apache /2 .0.61 (Unix)
Access-Control-Allow-Origin: http: //foo .example
Vary: Accept-Encoding Content-Encoding: gzip
Content-Length: 235 Keep-Alive: timeout=2, max=99 Connection: Keep-Alive Content-Type: text /plain
[Some GZIP'd payload] |
Lines 1 - 12 above represent the preflight request with the OPTIONS
header. Firefox 3.1 determines that it needs to send this based on the request parameters that the JavaScript code snippet above was using, so that the server can respond whether it is acceptable to send the request with the actual request parameters. OPTIONS is an HTTP/1.1 method that is used to determine further information from servers, and is an idempotent method, meaning that it can't be used to change the resource. Note that along with the OPTIONS request, two other request headers are sent (lines 11 and 12 respectively):
Access-Control-Request-Method: POST Access-Control-Request-Headers: X-PINGOTHER
The Access-Control-Request-Method
header notifies the server as part of a preflight request that when the actual request is sent, it will be sent with a POST
request method. The Access-Control-Request-Headers
header notifies the server that when the actual request is sent, it will be sent with an X-PINGOTHER
custom header. The server now has an opportunity to determine whether it wishes to accept a request under these circumstances.
Lines 15 - 27 above are the response that the server sends back indicating that the request method (POST
) and request headers (X-PINGOTHER
) are acceptable. In particular, let's look at lines 18-21:
Access-Control-Allow-Origin: http://foo.example Access-Control-Allow-Methods: POST, GET, OPTIONS Access-Control-Allow-Headers: X-PINGOTHER Access-Control-Max-Age: 1728000
The server responds with Access-Control-Allow-Methods
and says that POST
, GET
, and OPTIONS
are viable methods to query the resource in question. Note that this header is similar to the HTTP/1.1 Allow: response header, but used strictly within the context of access control. The server also sends Access-Control-Allow-Headers
with a value of X-PINGOTHER
, confirming that this is a permitted header to be used with the actual request. Like Access-Control-Allow-Methods
, Access-Control-Allow-Headers
is a comma separated list of acceptable headers. Finally, Access-Control-Max-Age
gives the value in seconds for how long the response to the preflight request can be cached for without sending another preflight request. In this case, 1728000 seconds is 20 days.
Requests with credentials
The most interesting capability exposed by both XMLHttpRequest
and Access Control is the ability to make "credentialed" requests that are cognizant of HTTP Cookies and HTTP Authentication information. By default, in cross-site XMLHttpRequest
invocations, browsers will not send credentials. A specific flag has to be set on the XMLHttpRequest
object when it is invoked.
In this example, content originally loaded from http://foo.example
makes a simple GET request to a resource on http://bar.other
which sets Cookies. Content on foo.example might contain JavaScript like this:
1
2
3
4
5
6
7
8
9
10
|
var invocation = new XMLHttpRequest();
var url = 'http://bar.other/resources/credentialed-content/' ;
function callOtherDomain(){
if (invocation) {
invocation.open( 'GET' , url, true );
invocation.withCredentials = true ;
invocation.onreadystatechange = handler;
invocation.send();
}
|
Line 8 shows the flag on XMLHttpRequest
that has to be set in order to make the invocation with Cookies, namely the withCredentials
boolean value. By default, the invocation is made without Cookies. Since this is a simple GET
request, it is not preflighted, but the browser will reject any response that does not have the Access-Control-Allow-Credentials: true
header, and not make the response available to the invoking web content.
Here is a sample exchange between client and server:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
GET /resources/access-control-with-credentials/ HTTP /1 .1
Host: bar.other User-Agent: Mozilla /5 .0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko /20081130 Minefield /3 .1b3pre
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
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Connection: keep-alive Referer: http: //foo .example /examples/credential .html
Origin: http: //foo .example
Cookie: pageAccess=2 HTTP /1 .1 200 OK
Date: Mon, 01 Dec 2008 01:34:52 GMT Server: Apache /2 .0.61 (Unix) PHP /4 .4.7 mod_ssl /2 .0.61 OpenSSL /0 .9.7e mod_fastcgi /2 .4.2 DAV /2 SVN /1 .4.2
X-Powered-By: PHP /5 .2.6
Access-Control-Allow-Origin: http: //foo .example
Access-Control-Allow-Credentials: true
Cache-Control: no-cache Pragma: no-cache Set-Cookie: pageAccess=3; expires=Wed, 31-Dec-2008 01:34:53 GMT Vary: Accept-Encoding Content-Encoding: gzip
Content-Length: 106 Keep-Alive: timeout=2, max=100 Connection: Keep-Alive Content-Type: text /plain
[text /plain payload]
|
Although line 12 contains the Cookie destined for the content on http://bar.other
, if bar.other did not respond with an Access-Control-Allow-Credentials: true
(line 20) the response would be ignored and not made available to web content. Important note: when responding to a credentialed request, server must specify a domain, and cannot use wild carding. The above example would fail if the header was wildcarded as: Access-Control-Allow-Origin: *
. Since the Access-Control-Allow-Origin
explicitly mentions http://foo.example
, the credential-cognizant content is returned to the invoking web content. Note that in line 23, a further cookie is set.
All of these examples can be seen working here. The next section deals with the actual HTTP headers.
The HTTP response headers
This section lists the HTTP response headers that servers send back for access control requests as defined by the Cross-Origin Resource Sharing specification. The previous section gives an overview of these in action.
Access-Control-Allow-Origin
A returned resource may have one Access-Control-Allow-Origin
header, with the following syntax:
Access-Control-Allow-Origin: <origin> | *
The origin
parameter specifies a URI that may access the resource. The browser must enforce this. For requests without credentials, the server may specify "*" as a wildcard, thereby allowing any origin to access the resource.
For example, to allow http://mozilla.com to access the resource, you can specify:
Access-Control-Allow-Origin: http://mozilla.com
Access-Control-Expose-Headers
This header lets a server whitelist headers that browsers are allowed to access. For example:
Access-Control-Expose-Headers: X-My-Custom-Header, X-Another-Custom-Header
This allows the X-My-Custom-Header
and X-Another-Custom-Header
headers to be exposed to the browser.
Access-Control-Max-Age
This header indicates how long the results of a preflight request can be cached. For an example of a preflight request, see the above examples.
Access-Control-Max-Age: <delta-seconds>
The delta-seconds
parameter indicates the number of seconds the results can be cached.
Access-Control-Allow-Credentials
Indicates whether or not the response to the request can be exposed when the credentials
flag is true. When used as part of a response to a preflight request, this indicates whether or not the actual request can be made using credentials. Note that simple GET
requests are not preflighted, and so if a request is made for a resource with credentials, if this header is not returned with the resource, the response is ignored by the browser and not returned to web content.
Access-Control-Allow-Credentials: true | false
Credentialed requests are discussed above.
Access-Control-Allow-Methods
Specifies the method or methods allowed when accessing the resource. This is used in response to a preflight request. The conditions under which a request is preflighted are discussed above.
Access-Control-Allow-Methods: <method>[, <method>]*
An example of a preflight request is given above, including an example which sends this header to the browser.
Access-Control-Allow-Headers
Used in response to a preflight request to indicate which HTTP headers can be used when making the actual request.
Access-Control-Allow-Headers: <field-name>[, <field-name>]*
The HTTP request headers
This section lists headers that clients may use when issuing HTTP requests in order to make use of the cross-origin sharing feature. Note that these headers for you when making invocations to servers. Developers using cross-site XMLHttpRequest
capability do not have to set any cross-origing sharing request headers programmatically.
Origin
Indicates the origin of the cross-site access request or preflight request.
Origin: <origin>
The origin is a URI indicating the server from which the request initiated. It does not include any path information, but only the server name.
origin
can be the empty string; this is useful, for example, if the source is a data
URL.Note that in any access control request, the ORIGIN
header is always sent.
Access-Control-Request-Method
Used when issuing a preflight request to let the server know what HTTP method will be used when the actual request is made.
Access-Control-Request-Method: <method>
Examples of this usage can be found above.
Access-Control-Request-Headers
Used when issuing a preflight request to let the server know what HTTP headers will be used when the actual request is made.
Access-Control-Request-Headers: <field-name>[, <field-name>]*
Examples of this usage can be found above.
Browser compatibility
Basic support | 4 | 3.5 | 8 (via XDomainRequest) 10 |
12 | 4 |
Note
Internet Explorer 8 and 9 expose CORS via the XDomainRequest object, but have a full implementation in IE 10. While Firefox 3.5 introduced support for cross-site XMLHttpRequests and Web Fonts, certain requests were limited until later versions. Specifically, Firefox 7 introduced the ability for cross-site HTTP requests for WebGL Textures, and Firefox 9 added support for Images drawn on a canvas using drawImage.
See also
- Code Samples Showing
XMLHttpRequest
and Cross-Origin Resource Sharing - Cross-Origing Resource Sharing From a Server-Side Perspective (PHP, etc.)
- Cross-Origin Resource Sharing specification
XMLHttpRequest
- Further Discussion of the Origin Header
- Using CORS with All (Modern) Browsers
The original article is at : https://developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS?redirectlocale=en-US&redirectslug=HTTP_access_control#Preflighted_requests
相关推荐
这个“标题”提到的“allow-cors-access-control插件”显然是针对这一机制的一个工具,旨在帮助前端开发者简化跨域Ajax请求的处理过程。 在Web开发中,AJAX(Asynchronous JavaScript and XML)是一种创建动态网页...
标题“TOMCAT 跨域 CORS Access-Control-Allow-Origin cors-filter”提及的是在Tomcat服务器上实现CORS策略的一种方式,主要涉及到`Access-Control-Allow-Origin`这个关键的响应头。 `Access-Control-Allow-Origin`...
名称:Allow CORS Access-Control-Allow ---------------------------------------- 版本:0.1.9 作者:Muyor 分类:生产工具 ---------------------------------------- 概述:轻松将(Access-Control-Allow-Origin...
标题中的“谷歌跨域插件allow-cors-access-control.zip”指的是一个用于解决浏览器跨域问题的Chrome插件。跨域资源共享(CORS)是一种机制,它允许Web应用程序从不同的源请求资源,比如JavaScript通过Ajax从非同源的...
`allow-cors-access-control` 插件就是为了解决这一问题而诞生的,它允许我们绕过浏览器的同源策略,方便地在Chrome浏览器上进行跨域请求。 `allow-cors-access-control` 插件的核心功能在于启用CORS(Cross-Origin...
标题 "allow-cors-access-control插件.zip" 指向的是一款用于解决跨域问题的Google浏览器插件。跨域资源共享(CORS)是Web开发中的一个重要概念,它允许浏览器在执行JavaScript时请求原本禁止的来自不同源的资源。这...
4. CORS与其他HTTP头部(如Access-Control-Allow-Methods、Access-Control-Allow-Headers)的配合使用。 5. 遇到跨域问题时的调试技巧和常见错误处理。 对于学习Web开发的人来说,理解和掌握CORS以及Access-Control...
在Chrome浏览器中,虽然默认遵循同源策略,但为方便开发者测试和调试,存在一种称为"allow-cors-access-control"的Chrome插件。这个插件的作用是允许用户绕过同源策略,实现跨域请求。安装后,它会修改浏览器的安全...
允许CORS:通过Access-Control-Allow-Origin,您可以轻松地在Web应用程序中执行跨域Ajax请求。 只需激活插件并执行请求。默认情况下(在JavaScript API中),CORS或跨源资源共享在现代浏览器中被阻止。安装此加载项...
标题中的"allow-cors-access-control.zip"提示我们这个压缩包包含了一个与跨域资源共享(CORS)相关的插件。跨域资源共享是一种网络浏览器的安全策略,它限制了网页从一个源加载资源到另一个不同的源,除非服务器...
Access-Control-Allow-Origin是HTTP响应头的一部分,用于指定允许哪些源的请求访问服务器资源。 描述中提到的插件主要是为了解决跨域限制,让开发者在开发和测试阶段能够方便地进行跨域请求。在实际开发中,我们...
`Access-Control-Allow-Origin`是CORS机制中的关键头部,用于指定允许哪些源进行跨域请求。 **一、CORS的基本原理** 1. **预检请求(Preflight Request)**:对于某些可能对服务器有副作用的HTTP请求方法(如PUT、...
谷歌Access-Control-Allow-Origin插件,Allow CORS: Access-Control-Allow-Origin lets you easily perform cross-domain Ajax requests in web applications.
2. CORS(Cross-Origin Resource Sharing):现代浏览器支持的跨域方式,通过设置Access-Control-Allow-Origin等CORS相关的响应头,允许特定或所有源进行跨域请求。CORS支持所有HTTP方法,并提供了完整的错误处理机制...
语言:English 轻松添加(访问 - 控制 - 允许 - 源:*)规则... 如果您有一个功能请求,或者发现要报告的错误,请填写加载项的主页中的错误报告表单(https://mybrowseraddon.com/access-control-allow-origin.html)。
"Access-Control-Allow-Origin"是CORS机制中关键的响应头字段,用于控制资源是否可以被其他源的页面访问。本文将详细讲解这一概念,并结合Chrome浏览器的使用,深入探讨其实际应用。 首先,"Access-Control-Allow-...
4. CORS的其他相关响应头:还包括`Access-Control-Allow-Methods`(指定允许的HTTP方法)、`Access-Control-Allow-Headers`(指定允许的请求头)、`Access-Control-Max-Age`(缓存预检请求的秒数)等。 5. Chrome...
2. `Access-Control-Allow-Methods`:允许的HTTP请求方法,如GET、POST、PUT等。 3. `Access-Control-Allow-Headers`:允许客户端在请求中携带的自定义头部,比如X-Requested-With。 4. `Access-Control-Allow-...
容器(Docker)中的CORS代理,用于您需要Access-Control-Allow-Origin: * ! 您可以使用CORS容器,而无需通过Heroku自行运行(它是在免费的dyno上,因此初始启动时间可能很慢!) 。 关于 如果您需要前端项目的允许...