啟用 ASP.NET Core 中的跨原始來源要求(CORS)Enable Cross-Origin Requests (CORS) in ASP.NET Core

Rick Anderson 提供By Rick Anderson

本文說明如何在 ASP.NET Core 應用程式中啟用 CORS。This article shows how to enable CORS in an ASP.NET Core app.

瀏覽器安全性可防止網頁向不同于服務網頁的網域提出要求。Browser security prevents a web page from making requests to a different domain than the one that served the web page. 這種限制稱為「相同來源原則」。This restriction is called the same-origin policy. 相同來源的原則可防止惡意網站從另一個網站讀取敏感性資料。The same-origin policy prevents a malicious site from reading sensitive data from another site. 有時候,您可能會想要允許其他網站向您的應用程式發出跨原始來源要求。Sometimes, you might want to allow other sites make cross-origin requests to your app. 如需詳細資訊,請參閱MOZILLA CORS 一文For more information, see the Mozilla CORS article.

跨原始來源資源分享(CORS):Cross Origin Resource Sharing (CORS):

  • 是一種 W3C 標準,可讓伺服器放寬相同的來源原則。Is a W3C standard that allows a server to relax the same-origin policy.
  • 是安全性功能,CORS 放寬安全性。Is not a security feature, CORS relaxes security. 藉由允許 CORS,API 不會更安全。An API is not safer by allowing CORS. 如需詳細資訊,請參閱CORS 的運作方式For more information, see How CORS works.
  • 允許伺服器明確允許某些跨原始來源要求,同時拒絕其他要求。Allows a server to explicitly allow some cross-origin requests while rejecting others.
  • 比先前的技術更安全且更具彈性,例如JSONPIs safer and more flexible than earlier techniques, such as JSONP.

檢視或下載範例程式碼 (英文) (如何下載)View or download sample code (how to download)

相同的來源Same origin

如果兩個 Url 具有相同的配置、主機和埠(RFC 6454),就會有相同的來源。Two URLs have the same origin if they have identical schemes, hosts, and ports (RFC 6454).

這兩個 Url 具有相同的來源:These two URLs have the same origin:

  • https://example.com/foo.html
  • https://example.com/bar.html

這些 Url 的來源不同于前兩個 Url:These URLs have different origins than the previous two URLs:

  • https://example.net – 個不同的網域https://example.net – Different domain
  • https://www.example.com/foo.html – 個不同的子域https://www.example.com/foo.html – Different subdomain
  • http://example.com/foo.html – 個不同的配置http://example.com/foo.html – Different scheme
  • https://example.com:9000/foo.html – 個不同的埠https://example.com:9000/foo.html – Different port

在比較原始來源時,Internet Explorer 不會考慮此埠。Internet Explorer doesn't consider the port when comparing origins.

具有已命名原則和中介軟體的 CORSCORS with named policy and middleware

CORS 中介軟體會處理跨原始來源要求。CORS Middleware handles cross-origin requests. 下列程式碼會針對具有指定來源的整個應用程式啟用 CORS:The following code enables CORS for the entire app with the specified origin:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins";

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddCors(options =>
        {
            options.AddPolicy(MyAllowSpecificOrigins,
            builder =>
            {
                builder.WithOrigins("http://example.com",
                                    "http://www.contoso.com");
            });
        });

        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseHsts();
        }

        app.UseCors(MyAllowSpecificOrigins); 

        app.UseHttpsRedirection();
        app.UseMvc();
    }
}

上述程式碼:The preceding code:

  • 將原則名稱設定為 "_myAllowSpecificOrigins"。Sets the policy name to "_myAllowSpecificOrigins". 原則名稱是任意的。The policy name is arbitrary.
  • 呼叫 @no__t 0 擴充方法,以啟用 CORS。Calls the UseCors extension method, which enables CORS.
  • 使用lambda 運算式呼叫 AddCorsCalls AddCors with a lambda expression. Lambda 會接受 @no__t 0 的物件。The lambda takes a CorsPolicyBuilder object. WithOrigins 等設定選項會在本文稍後說明。Configuration options, such as WithOrigins, are described later in this article.

@No__t-0 方法呼叫會將 CORS 服務新增至應用程式的服務容器:The AddCors method call adds CORS services to the app's service container:

public void ConfigureServices(IServiceCollection services)
{
    services.AddCors(options =>
    {
        options.AddPolicy(MyAllowSpecificOrigins,
        builder =>
        {
            builder.WithOrigins("http://example.com",
                                "http://www.contoso.com");
        });
    });

    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}

如需詳細資訊,請參閱本檔中的CORS 原則選項For more information, see CORS policy options in this document .

@No__t-0 方法可以連鎖方法,如下列程式碼所示:The CorsPolicyBuilder method can chain methods, as shown in the following code:

public void ConfigureServices(IServiceCollection services)
{
    services.AddCors(options =>
    {
        options.AddPolicy(MyAllowSpecificOrigins,
        builder =>
        {
            builder.WithOrigins("http://example.com",
                                "http://www.contoso.com")
                                .AllowAnyHeader()
                                .AllowAnyMethod();
        });
    });

    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}

注意: URL能包含尾端斜線(/)。Note: The URL must not contain a trailing slash (/). 如果 URL 以 / 結束,則比較會傳回 false,而且不會傳回任何標頭。If the URL terminates with /, the comparison returns false and no header is returned.

將 CORS 原則套用至所有端點Apply CORS policies to all endpoints

下列程式碼會透過 CORS 中介軟體將 CORS 原則套用至所有應用程式端點:The following code applies CORS policies to all the apps endpoints via CORS Middleware:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    // Preceding code ommitted.
    app.UseRouting();

    app.UseCors();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });

    // Following code ommited.
}

警告

使用端點路由,必須將 CORS 中介軟體設定為在 UseRouting 的呼叫和 UseEndpoints 之間執行。With endpoint routing, the CORS middleware must be configured to execute between the calls to UseRouting and UseEndpoints. 不正確的設定會導致中介軟體停止正常運作。Incorrect configuration will cause the middleware to stop functioning correctly.

下列程式碼會透過 CORS 中介軟體將 CORS 原則套用至所有應用程式端點:The following code applies CORS policies to all the apps endpoints via CORS Middleware:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseHsts();
    }

    app.UseCors();

    app.UseHttpsRedirection();
    app.UseMvc();
}

注意:必須先呼叫 UseCors,才能 UseMvcNote: UseCors must be called before UseMvc.

請參閱在 Razor Pages、控制器和動作方法中啟用 cors ,以在頁面/控制器/動作層級套用 cors 原則。See Enable CORS in Razor Pages, controllers, and action methods to apply CORS policy at the page/controller/action level.

如需測試上述程式碼的指示,請參閱測試 CORSSee Test CORS for instructions on testing the preceding code.

使用端點路由來啟用 CorsEnable Cors with endpoint routing

使用端點路由,可以使用一組 @no__t 的擴充方法,以每個端點為基礎來啟用 CORS。With endpoint routing, CORS can be enabled on a per-endpoint basis using the RequireCors set of extension methods.

app.UseEndpoints(endpoints =>
{
  endpoints.MapGet("/echo", async context => context.Response.WriteAsync("echo"))
    .RequireCors("policy-name");
});

同樣地,您也可以針對所有控制器啟用 CORS:Similarly, CORS can also be enabled for all controllers:

app.UseEndpoints(endpoints =>
{
  endpoints.MapControllers().RequireCors("policy-name");
});

啟用具有屬性的 CORSEnable CORS with attributes

@No__t-1EnableCors @ no__t-2屬性提供全域套用 CORS 的替代方法。The [EnableCors] attribute provides an alternative to applying CORS globally. @No__t-0 屬性會啟用所選結束點的 CORS,而不是所有結束點。The [EnableCors] attribute enables CORS for selected end points, rather than all end points.

使用 [EnableCors] 來指定預設原則,並 [EnableCors("{Policy String}")] 指定原則。Use [EnableCors] to specify the default policy and [EnableCors("{Policy String}")] to specify a policy.

@No__t-0 屬性可以套用至:The [EnableCors] attribute can be applied to:

  • Razor 頁面 PageModelRazor Page PageModel
  • 控制器Controller
  • 控制器動作方法Controller action method

您可以使用 [EnableCors] 屬性,將不同的原則套用至控制器/頁面模型/動作。You can apply different policies to controller/page-model/action with the [EnableCors] attribute. [EnableCors] 屬性套用至控制器/頁面模型/動作方法,且在中介軟體中啟用 CORS 時,會套用這兩個原則。When the [EnableCors] attribute is applied to a controllers/page-model/action method, and CORS is enabled in middleware, both policies are applied. 我們建議您不要結合原則。We recommend against combining policies. 使用 [EnableCors] 屬性或中介軟體,而不是同時在相同的應用程式中。Use the [EnableCors] attribute or middleware, not both in the same app.

下列程式碼會將不同的原則套用至每個方法:The following code applies a different policy to each method:

[Route("api/[controller]")]
[ApiController]
public class WidgetController : ControllerBase
{
    // GET api/values
    [EnableCors("AnotherPolicy")]
    [HttpGet]
    public ActionResult<IEnumerable<string>> Get()
    {
        return new string[] { "green widget", "red widget" };
    }

    // GET api/values/5
    [EnableCors]        // Default policy.
    [HttpGet("{id}")]
    public ActionResult<string> Get(int id)
    {
        switch (id)
        {
            case 1:
                return "green widget";
            case 2:
                return "red widget";
            default:
                return NotFound();
        }
    }
}

下列程式碼會建立 CORS 預設原則和名為 "AnotherPolicy" 的原則:The following code creates a CORS default policy and a policy named "AnotherPolicy":

public class StartupMultiPolicy
{
    public StartupMultiPolicy(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddCors(options =>
        {
            options.AddDefaultPolicy(
                builder =>
                {
                   
                    builder.WithOrigins("http://example.com",
                                        "http://www.contoso.com");
                });

            options.AddPolicy("AnotherPolicy",
                builder =>
                {
                    builder.WithOrigins("http://www.contoso.com")
                                        .AllowAnyHeader()
                                        .AllowAnyMethod();
                });

        });

        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseMvc();
    }
}

停用 CORSDisable CORS

@No__t-1DisableCors @ no__t-2屬性會停用控制器/頁面模型/動作的 CORS。The [DisableCors] attribute disables CORS for the controller/page-model/action.

CORS 原則選項CORS policy options

本節說明可在 CORS 原則中設定的各種選項:This section describes the various options that can be set in a CORS policy:

Startup.ConfigureServices 中呼叫 AddPolicyAddPolicy is called in Startup.ConfigureServices. 針對某些選項,閱讀CORS 的運作方式一節可能會很有説明。For some options, it may be helpful to read the How CORS works section first.

設定允許的原始來源Set the allowed origins

AllowAnyOrigin – 允許所有來源的 CORS 要求,並搭配任何配置(httphttps)。AllowAnyOrigin – Allows CORS requests from all origins with any scheme (http or https). AllowAnyOrigin 不安全,因為任何網站都可以對應用程式發出跨原始來源要求。AllowAnyOrigin is insecure because any website can make cross-origin requests to the app.

注意

指定 AllowAnyOriginAllowCredentials 是不安全的設定,而且可能導致跨網站偽造要求。Specifying AllowAnyOrigin and AllowCredentials is an insecure configuration and can result in cross-site request forgery. 當應用程式已設定這兩種方法時,CORS 服務會傳回不正確 CORS 回應。The CORS service returns an invalid CORS response when an app is configured with both methods.

注意

指定 AllowAnyOriginAllowCredentials 是不安全的設定,而且可能導致跨網站偽造要求。Specifying AllowAnyOrigin and AllowCredentials is an insecure configuration and can result in cross-site request forgery. 針對安全的應用程式,如果用戶端必須授權自己來存取伺服器資源,請指定來源的確切清單。For a secure app, specify an exact list of origins if the client must authorize itself to access server resources.

AllowAnyOrigin 會影響預檢要求和 @no__t 1 標頭。AllowAnyOrigin affects preflight requests and the Access-Control-Allow-Origin header. 如需詳細資訊,請參閱預檢要求一節。For more information, see the Preflight requests section.

SetIsOriginAllowedToAllowWildcardSubdomains – 會將原則的 IsOriginAllowed 屬性設為函式,以便在評估是否允許來源時,讓來源符合已設定的萬用字元網域。SetIsOriginAllowedToAllowWildcardSubdomains – Sets the IsOriginAllowed property of the policy to be a function that allows origins to match a configured wildcard domain when evaluating if the origin is allowed.

options.AddPolicy("AllowSubdomain",
    builder =>
    {
        builder.WithOrigins("https://*.example.com")
            .SetIsOriginAllowedToAllowWildcardSubdomains();
    });

設定允許的 HTTP 方法Set the allowed HTTP methods

AllowAnyMethod:AllowAnyMethod:

  • 允許任何 HTTP 方法:Allows any HTTP method:
  • 會影響預檢要求和 @no__t 0 標頭。Affects preflight requests and the Access-Control-Allow-Methods header. 如需詳細資訊,請參閱預檢要求一節。For more information, see the Preflight requests section.

設定允許的要求標頭Set the allowed request headers

若要允許在 CORS 要求中傳送特定標頭(稱為author 要求標頭),請呼叫 WithHeaders,並指定允許的標頭:To allow specific headers to be sent in a CORS request, called author request headers, call WithHeaders and specify the allowed headers:

options.AddPolicy("AllowHeaders",
    builder =>
    {
        builder.WithOrigins("http://example.com")
               .WithHeaders(HeaderNames.ContentType, "x-custom-header");
    });

若要允許所有作者要求標頭,請呼叫 AllowAnyHeaderTo allow all author request headers, call AllowAnyHeader:

options.AddPolicy("AllowAllHeaders",
    builder =>
    {
        builder.WithOrigins("http://example.com")
               .AllowAnyHeader();
    });

此設定會影響預檢要求和 @no__t 0 標頭。This setting affects preflight requests and the Access-Control-Request-Headers header. 如需詳細資訊,請參閱預檢要求一節。For more information, see the Preflight requests section.

只有在 Access-Control-Request-Headers 中傳送的標頭完全符合 WithHeaders 中所述的標頭時,才可以將 CORS 中介軟體原則符合 WithHeaders 所指定的特定標頭。A CORS Middleware policy match to specific headers specified by WithHeaders is only possible when the headers sent in Access-Control-Request-Headers exactly match the headers stated in WithHeaders.

例如,假設有一個應用程式設定如下:For instance, consider an app configured as follows:

app.UseCors(policy => policy.WithHeaders(HeaderNames.CacheControl));

CORS 中介軟體會拒絕具有下列要求標頭的預檢要求,因為 Content-LanguageHeaderNames. ContentLanguage)未列在 WithHeadersCORS Middleware declines a preflight request with the following request header because Content-Language (HeaderNames.ContentLanguage) isn't listed in WithHeaders:

Access-Control-Request-Headers: Cache-Control, Content-Language

應用程式會傳回200 OK回應,但不會傳送 CORS 標頭。The app returns a 200 OK response but doesn't send the CORS headers back. 因此,瀏覽器不會嘗試跨原始來源要求。Therefore, the browser doesn't attempt the cross-origin request.

CORS 中介軟體一律允許傳送 @no__t 0 中的四個標頭,而不論 c 中設定的值為何。CORS Middleware always allows four headers in the Access-Control-Request-Headers to be sent regardless of the values configured in CorsPolicy.Headers. 此標頭清單包含:This list of headers includes:

  • Accept
  • Accept-Language
  • Content-Language
  • Origin

例如,假設有一個應用程式設定如下:For instance, consider an app configured as follows:

app.UseCors(policy => policy.WithHeaders(HeaderNames.CacheControl));

CORS 中介軟體會以下列要求標頭成功回應預檢要求,因為 Content-Language 一律會列入允許清單:CORS Middleware responds successfully to a preflight request with the following request header because Content-Language is always whitelisted:

Access-Control-Request-Headers: Cache-Control, Content-Language

設定公開的回應標頭Set the exposed response headers

根據預設,瀏覽器不會將所有的回應標頭公開給應用程式。By default, the browser doesn't expose all of the response headers to the app. 如需詳細資訊,請參閱W3C 跨原始來源資源分享(術語):簡單的回應標頭For more information, see W3C Cross-Origin Resource Sharing (Terminology): Simple Response Header.

預設可用的回應標頭為:The response headers that are available by default are:

  • Cache-Control
  • Content-Language
  • Content-Type
  • Expires
  • Last-Modified
  • Pragma

CORS 規格會呼叫這些標頭簡單的回應標頭The CORS specification calls these headers simple response headers. 若要讓應用程式使用其他標頭,請呼叫 WithExposedHeadersTo make other headers available to the app, call WithExposedHeaders:

options.AddPolicy("ExposeResponseHeaders",
    builder =>
    {
        builder.WithOrigins("http://example.com")
               .WithExposedHeaders("x-custom-header");
    });

跨原始來源要求中的認證Credentials in cross-origin requests

認證需要在 CORS 要求中進行特殊處理。Credentials require special handling in a CORS request. 根據預設,瀏覽器不會傳送具有跨原始來源要求的認證。By default, the browser doesn't send credentials with a cross-origin request. 認證包括 cookie 和 HTTP 驗證配置。Credentials include cookies and HTTP authentication schemes. 若要使用跨原始來源要求傳送認證,用戶端必須將 XMLHttpRequest.withCredentials 設定為 trueTo send credentials with a cross-origin request, the client must set XMLHttpRequest.withCredentials to true.

直接使用 XMLHttpRequestUsing XMLHttpRequest directly:

var xhr = new XMLHttpRequest();
xhr.open('get', 'https://www.example.com/api/test');
xhr.withCredentials = true;

使用 jQuery:Using jQuery:

$.ajax({
  type: 'get',
  url: 'https://www.example.com/api/test',
  xhrFields: {
    withCredentials: true
  }
});

使用FETCH APIUsing the Fetch API:

fetch('https://www.example.com/api/test', {
    credentials: 'include'
});

伺服器必須允許認證。The server must allow the credentials. 若要允許跨原始來源認證,請呼叫 AllowCredentialsTo allow cross-origin credentials, call AllowCredentials:

options.AddPolicy("AllowCredentials",
    builder =>
    {
        builder.WithOrigins("http://example.com")
               .AllowCredentials();
    });

HTTP 回應包含 Access-Control-Allow-Credentials 標頭,告訴瀏覽器伺服器允許跨原始來源要求的認證。The HTTP response includes an Access-Control-Allow-Credentials header, which tells the browser that the server allows credentials for a cross-origin request.

如果瀏覽器傳送認證,但回應未包含有效的 Access-Control-Allow-Credentials 標頭,則瀏覽器不會向應用程式公開回應,且跨原始來源要求會失敗。If the browser sends credentials but the response doesn't include a valid Access-Control-Allow-Credentials header, the browser doesn't expose the response to the app, and the cross-origin request fails.

允許跨原始來源認證會有安全性風險。Allowing cross-origin credentials is a security risk. 另一個網域的網站可以代表使用者將登入使用者的認證傳送給應用程式,而不需要使用者的知識。A website at another domain can send a signed-in user's credentials to the app on the user's behalf without the user's knowledge.

CORS 規格也會指出,如果有 @no__t 1 標頭,則將來源設定為 "*" (所有來源)是不正確。The CORS specification also states that setting origins to "*" (all origins) is invalid if the Access-Control-Allow-Credentials header is present.

預檢要求Preflight requests

針對某些 CORS 要求,瀏覽器會在提出實際要求之前傳送額外的要求。For some CORS requests, the browser sends an additional request before making the actual request. 此要求稱為預檢要求This request is called a preflight request. 當下列條件成立時,瀏覽器可以略過預檢要求:The browser can skip the preflight request if the following conditions are true:

  • 要求方法為 GET、HEAD 或 POST。The request method is GET, HEAD, or POST.
  • 應用程式不會設定 AcceptAccept-LanguageContent-LanguageContent-TypeLast-Event-ID 以外的要求標頭。The app doesn't set request headers other than Accept, Accept-Language, Content-Language, Content-Type, or Last-Event-ID.
  • 如果設定 Content-Type 標頭,就會有下列其中一個值:The Content-Type header, if set, has one of the following values:
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

針對用戶端要求設定的要求標頭規則會套用至應用程式所設定的標頭,方法是在 XMLHttpRequest 物件上呼叫 setRequestHeaderThe rule on request headers set for the client request applies to headers that the app sets by calling setRequestHeader on the XMLHttpRequest object. CORS 規格會呼叫這些標頭的作者要求標頭The CORS specification calls these headers author request headers. 此規則不適用於瀏覽器可以設定的標頭,例如 User-AgentHostContent-LengthThe rule doesn't apply to headers the browser can set, such as User-Agent, Host, or Content-Length.

以下是預檢要求的範例:The following is an example of a preflight request:

OPTIONS https://myservice.azurewebsites.net/api/test HTTP/1.1
Accept: */*
Origin: https://myclient.azurewebsites.net
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: accept, x-my-custom-header
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)
Host: myservice.azurewebsites.net
Content-Length: 0

預先飛行要求會使用 HTTP OPTIONS 方法。The pre-flight request uses the HTTP OPTIONS method. 其中包含兩個特殊標頭:It includes two special headers:

  • Access-Control-Request-Method:將用於實際要求的 HTTP 方法。Access-Control-Request-Method: The HTTP method that will be used for the actual request.
  • Access-Control-Request-Headers:應用程式在實際要求上設定的要求標頭清單。Access-Control-Request-Headers: A list of request headers that the app sets on the actual request. 如先前所述,這不會包含瀏覽器所設定的標頭,例如 User-AgentAs stated earlier, this doesn't include headers that the browser sets, such as User-Agent.

CORS 預檢要求可能會包含 Access-Control-Request-Headers 標頭,這會向伺服器指出與實際要求一起傳送的標頭。A CORS preflight request might include an Access-Control-Request-Headers header, which indicates to the server the headers that are sent with the actual request.

若要允許特定標頭,請呼叫 WithHeadersTo allow specific headers, call WithHeaders:

options.AddPolicy("AllowHeaders",
    builder =>
    {
        builder.WithOrigins("http://example.com")
               .WithHeaders(HeaderNames.ContentType, "x-custom-header");
    });

若要允許所有作者要求標頭,請呼叫 AllowAnyHeaderTo allow all author request headers, call AllowAnyHeader:

options.AddPolicy("AllowAllHeaders",
    builder =>
    {
        builder.WithOrigins("http://example.com")
               .AllowAnyHeader();
    });

瀏覽器在設定 Access-Control-Request-Headers 的方式上並不完全一致。Browsers aren't entirely consistent in how they set Access-Control-Request-Headers. 如果您將標頭設定為 "*" (或使用 AllowAnyHeader)以外的任何專案,您應該至少包含 AcceptContent-TypeOrigin,加上您想要支援的任何自訂標頭。If you set headers to anything other than "*" (or use AllowAnyHeader), you should include at least Accept, Content-Type, and Origin, plus any custom headers that you want to support.

以下是預檢要求的回應範例(假設伺服器允許此要求):The following is an example response to the preflight request (assuming that the server allows the request):

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Length: 0
Access-Control-Allow-Origin: https://myclient.azurewebsites.net
Access-Control-Allow-Headers: x-my-custom-header
Access-Control-Allow-Methods: PUT
Date: Wed, 20 May 2015 06:33:22 GMT

回應包含 Access-Control-Allow-Methods 標頭,其中會列出允許的方法,並可選擇是否使用 @no__t 1 標頭,其中會列出允許的標頭。The response includes an Access-Control-Allow-Methods header that lists the allowed methods and optionally an Access-Control-Allow-Headers header, which lists the allowed headers. 如果預檢要求成功,瀏覽器就會傳送實際的要求。If the preflight request succeeds, the browser sends the actual request.

如果預檢要求遭到拒絕,應用程式會傳回200 OK回應,但不會傳送 CORS 標頭。If the preflight request is denied, the app returns a 200 OK response but doesn't send the CORS headers back. 因此,瀏覽器不會嘗試跨原始來源要求。Therefore, the browser doesn't attempt the cross-origin request.

設定預檢到期時間Set the preflight expiration time

@No__t-0 標頭會指定可以快取對預檢要求回應的時間長度。The Access-Control-Max-Age header specifies how long the response to the preflight request can be cached. 若要設定此標頭,請呼叫 SetPreflightMaxAgeTo set this header, call SetPreflightMaxAge:

options.AddPolicy("SetPreflightExpiration",
    builder =>
    {
        builder.WithOrigins("http://example.com")
               .SetPreflightMaxAge(TimeSpan.FromSeconds(2520));
    });

CORS 的運作方式How CORS works

本節說明在 HTTP 訊息層級的CORS要求中會發生什麼事。This section describes what happens in a CORS request at the level of the HTTP messages.

  • CORS是安全性功能。CORS is not a security feature. CORS 是一種 W3C 標準,可讓伺服器放寬相同的原始原則。CORS is a W3C standard that allows a server to relax the same-origin policy.
    • 例如,惡意執行者可能會對您的網站使用防止跨網站腳本(XSS) ,並對其已啟用 CORS 的網站執行跨網站要求,以竊取資訊。For example, a malicious actor could use Prevent Cross-Site Scripting (XSS) against your site and execute a cross-site request to their CORS enabled site to steal information.
  • 藉由允許 CORS,您的 API 不會更安全。Your API is not safer by allowing CORS.
    • 而是由用戶端(瀏覽器)強制執行 CORS。It's up to the client (browser) to enforce CORS. 伺服器會執行要求並傳迴響應,這是傳回錯誤並封鎖回應的用戶端。The server executes the request and returns the response, it's the client that returns an error and blocks the response. 例如,下列任何一項工具都會顯示伺服器回應:For example, any of the following tools will display the server response:
  • 這是讓伺服器允許瀏覽器執行跨原始XHR提取 API要求的方式,否則會禁止。It's a way for a server to allow browsers to execute a cross-origin XHR or Fetch API request that otherwise would be forbidden.
    • 瀏覽器(不含 CORS)無法執行跨原始來源要求。Browsers (without CORS) can't do cross-origin requests. 在 CORS 之前, JSONP是用來規避這種限制。Before CORS, JSONP was used to circumvent this restriction. JSONP 不會使用 XHR,它會使用 <script> 標記來接收回應。JSONP doesn't use XHR, it uses the <script> tag to receive the response. 允許跨原始來源載入腳本。Scripts are allowed to be loaded cross-origin.

CORS 規格引進數個新的 HTTP 標頭,可啟用跨原始來源要求。The CORS specification introduced several new HTTP headers that enable cross-origin requests. 如果瀏覽器支援 CORS,它會針對跨原始來源要求自動設定這些標頭。If a browser supports CORS, it sets these headers automatically for cross-origin requests. 不需要自訂 JavaScript 程式碼來啟用 CORS。Custom JavaScript code isn't required to enable CORS.

以下是跨原始來源要求的範例。The following is an example of a cross-origin request. @No__t 0 標頭會提供提出要求的網站網域。The Origin header provides the domain of the site that's making the request. 需要 Origin 標頭,而且必須與主機不同。The Origin header is required and must be different from the host.

GET https://myservice.azurewebsites.net/api/test HTTP/1.1
Referer: https://myclient.azurewebsites.net/
Accept: */*
Accept-Language: en-US
Origin: https://myclient.azurewebsites.net
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)
Host: myservice.azurewebsites.net

如果伺服器允許此要求,它會在回應中設定 Access-Control-Allow-Origin 標頭。If the server allows the request, it sets the Access-Control-Allow-Origin header in the response. 此標頭的值會符合要求中的 @no__t 0 標頭,或為萬用字元值 "*",表示允許任何來源:The value of this header either matches the Origin header from the request or is the wildcard value "*", meaning that any origin is allowed:

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: text/plain; charset=utf-8
Access-Control-Allow-Origin: https://myclient.azurewebsites.net
Date: Wed, 20 May 2015 06:27:30 GMT
Content-Length: 12

Test message

如果回應不包含 @no__t 0 標頭,則跨原始來源要求會失敗。If the response doesn't include the Access-Control-Allow-Origin header, the cross-origin request fails. 具體而言,瀏覽器不允許此要求。Specifically, the browser disallows the request. 即使伺服器傳回成功的回應,瀏覽器也不會將回應提供給用戶端應用程式。Even if the server returns a successful response, the browser doesn't make the response available to the client app.

測試 CORSTest CORS

測試 CORS:To test CORS:

  1. 建立 API 專案Create an API project. 或者,您可以下載範例Alternatively, you can download the sample.
  2. 使用本檔中的其中一種方法來啟用 CORS。Enable CORS using one of the approaches in this document. 例如:For example:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseHsts();
    }

    // Shows UseCors with CorsPolicyBuilder.
    app.UseCors(builder =>
    {
        builder.WithOrigins("http://example.com",
                            "http://www.contoso.com",
                            "https://localhost:44375",
                            "https://localhost:5001");
    });

    app.UseHttpsRedirection();
    app.UseMvc();
}

警告

WithOrigins("https://localhost:<port>"); 只應用於測試範例應用程式,類似于下載範例程式碼WithOrigins("https://localhost:<port>"); should only be used for testing a sample app similar to the download sample code.

  1. 建立 web 應用程式專案(Razor Pages 或 MVC)。Create a web app project (Razor Pages or MVC). 此範例會使用 Razor Pages。The sample uses Razor Pages. 您可以在與 API 專案相同的方案中建立 web 應用程式。You can create the web app in the same solution as the API project.
  2. 將下列反白顯示的程式碼新增至Index. cshtml檔案:Add the following highlighted code to the Index.cshtml file:
@page
@model IndexModel
@{
    ViewData["Title"] = "Home page";
}

<div class="text-center">
    <h1 class="display-4">CORS Test</h1>
</div>

<div>
    <input type="button" value="Test" 
           onclick="requestVal('https://<web app>.azurewebsites.net/api/values')" />
    <span id='result'></span>
</div>

<script>
    function requestVal(uri) {
        const resultSpan = document.getElementById('result');

        fetch(uri)
            .then(response => response.json())
            .then(data => resultSpan.innerText = data)
            .catch(error => resultSpan.innerText = 'See F12 Console for error');
    }
</script>
  1. 在上述程式碼中,將 url: 'https://<web app>.azurewebsites.net/api/values/1', 取代為已部署應用程式的 URL。In the preceding code, replace url: 'https://<web app>.azurewebsites.net/api/values/1', with the URL to the deployed app.

  2. 部署 API 專案。Deploy the API project. 例如,部署至 AzureFor example, deploy to Azure.

  3. 從桌面執行 Razor Pages 或 MVC 應用程式,然後按一下 [測試] 按鈕。Run the Razor Pages or MVC app from the desktop and click on the Test button. 使用 F12 工具來檢查錯誤訊息。Use the F12 tools to review error messages.

  4. WithOrigins 移除 localhost 原點,然後部署應用程式。Remove the localhost origin from WithOrigins and deploy the app. 或者,使用不同的埠來執行用戶端應用程式。Alternatively, run the client app with a different port. 例如,從 Visual Studio 執行。For example, run from Visual Studio.

  5. 使用用戶端應用程式進行測試。Test with the client app. CORS 失敗會傳回錯誤,但 JavaScript 無法使用錯誤訊息。CORS failures return an error, but the error message isn't available to JavaScript. 使用 F12 工具中的 [主控台] 索引標籤來查看錯誤。Use the console tab in the F12 tools to see the error. 視瀏覽器而定,您會收到類似下列的錯誤(在 F12 工具主控台中):Depending on the browser, you get an error (in the F12 tools console) similar to the following:

    • 使用 Microsoft Edge:Using Microsoft Edge:

      SEC7120: [CORS] 在 https://webapi.azurewebsites.net/api/values/1 的跨原始來源資源的存取控制-允許來源回應標頭中找不到 https://localhost:44375 的來源 https://localhost:44375SEC7120: [CORS] The origin https://localhost:44375 did not find https://localhost:44375 in the Access-Control-Allow-Origin response header for cross-origin resource at https://webapi.azurewebsites.net/api/values/1

    • 使用 Chrome:Using Chrome:

      已由 CORS 原則封鎖在 https://webapi.azurewebsites.net/api/values/1 從原始位置 https://localhost:44375 的存取 XMLHttpRequest:要求的資源上沒有任何「存取控制-允許來源」標頭。Access to XMLHttpRequest at https://webapi.azurewebsites.net/api/values/1 from origin https://localhost:44375 has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

具有 CORS 功能的端點可以使用工具(例如FiddlerPostman)進行測試。CORS-enabled endpoints can be tested with a tool, such as Fiddler or Postman. 使用工具時,@no__t 0 標頭所指定之要求的來源,必須與接收要求的主機不同。When using a tool, the origin of the request specified by the Origin header must differ from the host receiving the request. 如果要求不是根據 Origin 標頭的值而跨原始來源If the request isn't cross-origin based on the value of the Origin header:

  • CORS 中介軟體不需要處理要求。There's no need for CORS Middleware to process the request.
  • 回應中不會傳回 CORS 標頭。CORS headers aren't returned in the response.

其他資源Additional resources