ASP.NET MVC / WebAPI 응용 프로그램에서 HTTP OPTIONS 동사를 지원하는 방법


80

MVC 4 / Web API 템플릿으로 시작하는 ASP.NET 웹 응용 프로그램을 설정했습니다. 정말 잘 작동하는 것 같습니다. 제가 아는 문제는 없습니다. Chrome과 Firefox를 사용하여 사이트를 방문했습니다. 나는 Fiddler를 사용하여 테스트했으며 모든 응답이 돈에있는 것 같습니다.

이제이 새로운 웹 API를 사용하기 위해 간단한 Test.aspx를 작성하겠습니다. 스크립트의 관련 부분 :

<script type="text/javascript">
    $(function () {

        $.ajax({
            url: "http://mywebapidomain.com/api/user",
            type: "GET",
            contentType: "json",
            success: function (data) {

                $.each(data, function (index, item) {

                    ....

                    });
                }
                );

            },
            failure: function (result) {
                alert(result.d);
            },

            error: function (XMLHttpRequest, textStatus, errorThrown) {
                alert("An error occurred, please try again. " + textStatus);
            }

        });

    });
</script>

REQUEST 헤더가 생성됩니다.

OPTIONS http://host.mywebapidomain.com/api/user HTTP/1.1
Host: host.mywebapidomain.com
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:24.0) Gecko/20100101 Firefox/24.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
Origin: http://mywebapidomain.com
Access-Control-Request-Method: GET
Access-Control-Request-Headers: content-type
Connection: keep-alive

그대로 Web API는 405 Method Not Allowed를 반환합니다.

HTTP/1.1 405 Method Not Allowed
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/xml; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Mon, 30 Sep 2013 13:28:12 GMT
Content-Length: 96

<Error><Message>The requested resource does not support http method 'OPTIONS'.</Message></Error>

OPTIONS 동사가 기본적으로 Web API 컨트롤러에 연결되어 있지 않다는 것을 이해합니다. 그래서 다음 코드를 UserController.cs에 배치했습니다.

// OPTIONS http-verb handler
public HttpResponseMessage OptionsUser()
{
    var response = new HttpResponseMessage();
    response.StatusCode = HttpStatusCode.OK;
    return response;
}

... 이것은 405 Method Not Allowed 오류를 제거했지만 응답이 완전히 비어 있습니다. 데이터가 반환되지 않습니다.

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Expires: -1
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Mon, 30 Sep 2013 12:56:21 GMT
Content-Length: 0

추가 논리가 있어야합니다 ... Options 메서드를 올바르게 코딩하는 방법이나 컨트롤러가 코드를 넣을 적절한 위치인지 모르겠습니다. Web API 사이트가 Firefox 또는 Chrome에서 볼 때 제대로 응답하지만 위의 .ajax 호출은 오류가 발생한다는 것이 이상합니다. .ajax 코드에서 "프리 플라이트"검사를 어떻게 처리합니까? 클라이언트 측의 .ajax 로직에서이 문제를 해결해야할까요? 또는 OPTIONS 동사를 처리하지 않아 서버 측에서 문제가되는 경우.

누구든지 도울 수 있습니까? 이것은 매우 일반적인 문제임에 틀림 없으며 여기에서 답변을 받으 셨다면 사과드립니다. 검색했지만 도움이되는 답변을 찾지 못했습니다.

IMHO 업데이트 , 이것은 클라이언트 측 문제이며 위의 Ajax JQuery 코드와 관련이 있습니다. 웹 브라우저에서 mywebapidomain / api / user에 액세스 할 때 Fiddler가 405 오류 헤더를 표시하지 않기 때문에 이렇게 말합니다. 이 문제를 복제 할 수있는 유일한 곳은 JQuery .ajax () 호출입니다. 또한 위의 동일한 Ajax 호출은 서버 (동일한 도메인)에서 실행될 때 제대로 작동합니다.

다른 게시물을 찾았습니다. Prototype AJAX 요청이 GET이 아닌 OPTIONS로 전송되었습니다. 관련된 것처럼 보이는 501 오류가 발생 했지만 성공하지 못한 제안을 수정했습니다. 분명히 JQuery는 Ajax 요청이 도메인 간 (내 것이있는) 경우 OPTIONS 헤더를 트리거하는 두 개의 헤더를 추가하도록 코딩되어 있습니다.

'X-Requested-With': 'XMLHttpRequest',
'X-Prototype-Version': Prototype.Version,

JQuery에서 핵심 코드를 수정하는 것보다 더 나은 솔루션이있을 것 같습니다.

아래 제공된 답변은 이것이 서버 측 문제라고 가정합니다. 아마도, 나는 고객에게 의지하고 호스팅 제공 업체에 전화하는 것이 도움이되지 않을 것입니다.


옵션 요청과 함께 무엇을 보내시겠습니까?
다니엘 A. 화이트

OPTIONS 요청을 전혀 보낼 필요가 없습니다. 어떤 이유로 이것은 Ajax 호출이 교차 도메인으로 이루어질 때 수행됩니다. 따라서 Javascript에서 볼 수 있듯이 GET을 지정하는 것이지만 OPTIONS 헤더는 HTTP 프로토콜로 인해 전송됩니다. "프리 플라이트"확인입니다.
rwkiii 2013 년

2
iis 서버에서 cors를 활성화해야합니다.
다니엘 A. 화이트

Arvixe 서버-Business Class Pro입니다. 두 사이트는 동일한 물리적 서버, 동일한 호스팅 계정에서 호스팅됩니다. 단지 다른 호스트 이름. CORS는 Arvixe를 호출하지 않고도 활성화 할 수 있습니까?
rwkiii 2013 년

호스팅 제공 업체에 전화하겠습니다.
Daniel A. White

답변:


52

Daniel A. White가 그의 의견에서 말했듯이 OPTIONS 요청은 교차 도메인 JavaScript 요청의 일부로 클라이언트에 의해 생성 될 가능성이 높습니다. 이것은 CORS (Cross Origin Resource Sharing) 호환 브라우저에 의해 자동으로 수행됩니다. 요청은 CORS에 대해 지원되는 요청 동사 및 헤더를 결정하기 위해 실제 AJAX 요청 전에 만들어진 예비 또는 사전 요청입니다. 서버는 HTTP 동사의 전부 또는 일부에 대해 지원하도록 선택할 수 있습니다.

그림을 완성하기 위해 AJAX 요청에는 JavaScript를 호스팅하는 원본 페이지가 제공되는 위치를 식별하는 추가 "Origin"헤더가 있습니다. 서버는 모든 출처의 요청을 지원하거나 알려진 신뢰할 수있는 출처 세트에 대해서만 지원하도록 선택할 수 있습니다. 출처를 허용하는 것은 CSRF (Cross Site Request Forgery)의 위험을 증가시킬 수 있으므로 보안 위험입니다.

따라서 CORS를 활성화해야합니다.

다음은 ASP.Net Web API에서이 작업을 수행하는 방법을 설명하는 링크입니다.

http://www.asp.net/web-api/overview/security/enabling-cross-origin-requests-in-web-api#enable-cors

여기에 설명 된 구현을 통해 무엇보다도

  • 작업 별, 컨트롤러 별 또는 글로벌 기반의 CORS 지원
  • 지원되는 출처
  • CORS aa 컨트롤러 또는 전역 수준을 활성화 할 때 지원되는 HTTP 동사
  • 서버가 원본 간 요청으로 자격 증명 보내기를 지원하는지 여부

일반적으로이 방법은 잘 작동하지만 특히 모든 도메인에서 원본 간 요청을 허용하는 경우 보안 위험을 인식하고 있는지 확인해야합니다. 이를 허용하기 전에 매우 신중하게 생각하십시오.

CORS를 지원하는 브라우저와 관련하여 Wikipedia는 다음 엔진이 CORS를 지원한다고 말합니다.

  • Gecko 1.9.1 (FireFox 3.5)
  • WebKit (Safari 4, Chrome 3)
  • IE8 및 9에서 부분적으로 지원되는 MSHTML / Trident 6 (IE10)
  • Presto (Opera 12)

http://en.wikipedia.org/wiki/Cross-origin_resource_sharing#Browser_support


안녕 마이크. 링크 주셔서 감사합니다. 여기에도 좋은 또 다른 것이 있습니다 : codeguru.com/csharp/.net/net_asp/…- 둘 다 나에게 문제를 아직 해결하지 못했지만. 지금은 테스트 페이지를 서버에 배치했으며 단기적으로는 도움이됩니다. Microsoft.AspNet.WebApi.Cors 설치를 시도했지만 내 앱에 WebApi 종속성이 없어서 설치가 롤백되었다는 이상한 오류가 발생했습니다. 답변 해주셔서 감사합니다. 맞습니다. +1!
rwkiii

@rwkiii 링크는 실제로 Web API 5.2.2에 대한 종속성을 추가하는 솔루션이지만 솔루션은 MVC가 OPTIONS 사전 요청을 지원하도록 강제하는 해킹보다 더 확장 가능합니다. 또한 클라이언트에서 이러한 호출을 필요로 수락 또는 콘텐츠 형식 헤더의 결과가 될 수있는 비행 전 요청으로 도미닉의 답변을 검토 할 수 있습니다
Sudhanshu 슈라을

참고 사항이지만 콘텐츠 유형을 'application / x-www-form-urlencoded', 'multipart / form-data'또는 'text / plain'으로 설정하면 요청이 '단순'으로 간주되고 비행 전 요청.
mbx-mbx 2015 년

94

Mike Goodwin의 답변은 훌륭하지만 시도했을 때 MVC5 / WebApi 2.1을 겨냥한 것 같습니다. Microsoft.AspNet.WebApi.Cors에 대한 종속성은 내 MVC4 프로젝트에서 잘 작동하지 않았습니다.

MVC4로 WebApi에서 CORS를 활성화하는 가장 간단한 방법은 다음과 같습니다.

모든 것을 허용했습니다. Origin의 API를 제공 할 클라이언트로 제한하는 것이 좋습니다. 모든 것을 허용하는 것은 보안 위험입니다.

Web.config :

<system.webServer>
    <httpProtocol>
      <customHeaders>
        <add name="Access-Control-Allow-Origin" value="*" />
        <add name="Access-Control-Allow-Methods" value="GET, PUT, POST, DELETE, HEAD" />
        <add name="Access-Control-Allow-Headers" value="Origin, X-Requested-With, Content-Type, Accept" />
      </customHeaders>
    </httpProtocol>
</system.webServer>

BaseApiController.cs :

OPTIONS http 동사를 허용하기 위해 이렇게합니다.

 public class BaseApiController : ApiController
  {
    public HttpResponseMessage Options()
    {
      return new HttpResponseMessage { StatusCode = HttpStatusCode.OK };
    }
  }

@Castaldi 제공된 답변이 Attribute Routing이없는 WebApi 1을 겨냥했기 때문일 수 있습니다. WebApi 2의 경우 Microsoft의 CORS nuget 패키지를 사용하는 것이 좋습니다. nuget.org/packages/Microsoft.AspNet.WebApi.Cors
올리버

[ApiExplorerSettings (IgnoreApi = true)]를 사용하여 Swagger의 OPTIONS 끝점을 무시할 수도 있습니다.
Mário Meyrelles

이것은 내 WebApi 2 앱에서 작동했습니다. 해당 / 기지국 제어기 특히 옵션 () 메소드
lazyList

24

이를 Application_OnBeginRequest메서드에 추가하고 (이렇게하면 애플리케이션에 대한 CORS 지원이 전역 적으로 활성화 됨) 프리 플라이트 요청을 "처리"합니다.

var res = HttpContext.Current.Response;
var req = HttpContext.Current.Request;
res.AppendHeader("Access-Control-Allow-Origin", req.Headers["Origin"]);
res.AppendHeader("Access-Control-Allow-Credentials", "true");
res.AppendHeader("Access-Control-Allow-Headers", "Content-Type, X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Date, X-Api-Version, X-File-Name");
res.AppendHeader("Access-Control-Allow-Methods", "POST,GET,PUT,PATCH,DELETE,OPTIONS");

// ==== Respond to the OPTIONS verb =====
if (req.HttpMethod == "OPTIONS")
{
    res.StatusCode = 200;
    res.End();
}

* 보안 : 이것은 어디에서나 서버로의 ajax 요청을 활성화한다는 점에 유의하십시오 (원하는 경우 쉼표로 구분 된 출처 / URL 목록 만 허용 할 수 있음).

대신 현재 클라이언트 원본을 사용했습니다. *왜냐하면 자격 증명 => Access-Control-Allow-Credentialstrue로 설정하면 크로스 브라우저 세션 관리가 가능하기 때문입니다.

또한 webconfig섹션 에서 삭제 및 배치, 패치 및 옵션 동사를 활성화해야합니다 system.webServer. 그렇지 않으면 IIS에서 차단합니다.

<handlers>
  <remove name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" />
  <remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />
  <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
  <add name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
  <add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
  <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>

도움이 되었기를 바랍니다


3
감사. 이것 만이 Application_OnBeginRequest나를 도왔습니다. 하지만 인증을 통해 데이터를 얻으려면 다음 항목도 추가해야 Authorization합니다.Access-Control-Allow-Headers
Ehsan88

18

Web API 2 프로젝트에서 동일한 문제가 발생한 후 (여기에 들어갈 가치가없는 이유로 표준 CORS 패키지를 사용할 수 없음) 사용자 지정 DelagatingHandler를 구현하여이 문제를 해결할 수있었습니다.

public class AllowOptionsHandler : DelegatingHandler
{
    protected override async Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var response = await base.SendAsync(request, cancellationToken);

        if (request.Method == HttpMethod.Options &&
            response.StatusCode == HttpStatusCode.MethodNotAllowed)
        {
            response = new HttpResponseMessage(HttpStatusCode.OK);
        }

        return response;
    }
}

Web API 구성의 경우 :

config.MessageHandlers.Add(new AllowOptionsHandler());

여기에 게시 된 다른 답변과 유사하게 Web.config에서 CORS 헤더가 활성화되어 있습니다.

<system.webServer>
  <modules runAllManagedModulesForAllRequests="true">
    <remove name="WebDAVModule" />
  </modules>

  <httpProtocol>
    <customHeaders>
      <add name="Access-Control-Allow-Origin" value="*" />
      <add name="Access-Control-Allow-Headers" value="accept, cache-control, content-type, authorization" />
      <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
    </customHeaders>
  </httpProtocol>

  <handlers>
    <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
    <remove name="TRACEVerbHandler" />
    <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
  </handlers>
</system.webServer>

내 프로젝트에는 MVC가 포함되지 않고 Web API 2 만 포함되어 있습니다.


10

나는 global.asax의 사용자 정의 코드에 의해서만 pre-flight ajax 옵션 요청에 던져진 405 및 404 오류를 극복했습니다.

protected void Application_BeginRequest()
    {            
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
        if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
        {
            //These headers are handling the "pre-flight" OPTIONS call sent by the browser
            HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, OPTIONS");
            HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
            HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
            HttpContext.Current.Response.End();
        }
    }

PS : 모든 것을 허용 할 때 보안 문제 고려 *.

'Access-Control-Allow-Origin'헤더에 여러 값이 포함되어 있기 때문에 CORS를 비활성화해야했습니다.

web.config에서도 필요했습니다.

<handlers>
  <remove name="ExtensionlessUrlHandler-Integrated-4.0"/>
  <remove name="OPTIONSVerbHandler"/>
  <remove name="TRACEVerbHandler"/>
  <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0"/>
</handlers>

그리고 app.pool을 통합 모드로 설정해야합니다.


8

나는 이와 같은 문제가 있었다. 나에게 수정은 jQuery AJAX 호출에서 사용자 정의 컨텐츠 유형을 제거하는 것이 었습니다. 사용자 지정 콘텐츠 유형은 비행 전 요청을 트리거합니다. 나는 이것을 찾았다:

브라우저는 다음 조건이 참인 경우 프리 플라이트 요청을 건너 뛸 수 있습니다.

요청 방법은 GET, HEAD또는 POST,

응용 프로그램이 아닌 다른 요청 헤더를 설정하지 않습니다 Accept, Accept-Language, Content-Language, Content-Type, 또는 Last-Event-ID,

Content-Type헤더 (설정 한 경우) 다음 중 하나입니다 :

  • application/x-www-form-urlencoded
  • multipart/form-data
  • text/plain

이 페이지에서 : http://www.asp.net/web-api/overview/security/enabling-cross-origin-requests-in-web-api("Preflight Requests "아래)



2
    protected void Application_EndRequest()
    {
        if (Context.Response.StatusCode == 405 && Context.Request.HttpMethod == "OPTIONS" )
        {
            Response.Clear();
            Response.StatusCode = 200;
            Response.End();
        }
    }

1

나도 같은 문제에 직면했습니다.

브라우저에서 (CORS) 준수 문제를 해결하려면 아래 단계를 따르십시오.

Cors 참조와 함께 솔루션에 REDRock을 포함하십시오. Web API 솔루션에 대한 WebActivatorEx 참조를 포함합니다.

그런 다음 Web API App_Start 폴더에 CorsConfig 파일을 추가합니다.

[assembly: PreApplicationStartMethod(typeof(WebApiNamespace.CorsConfig), "PreStart")]

namespace WebApiNamespace
{
    public static class CorsConfig
    {
        public static void PreStart()
        {
            GlobalConfiguration.Configuration.MessageHandlers.Add(new RedRocket.WebApi.Cors.CorsHandler());
        }
    }
}

이러한 변경을 통해 모든 브라우저에서 webapi에 액세스 할 수있었습니다.


4
redrock은 무엇입니까? Google 검색과 Nuget 패키지 검색을 수행했지만 아무것도 반환되지 않았습니다. 링크가 좋을 것입니다.
hofnarwillie

1

나는 같은 문제가 있었고 이것이 내가 그것을 고친 방법입니다.

web.config에 이것을 던져 넣으십시오.

<system.webServer>
    <modules>
      <remove name="WebDAVModule" />
    </modules>

    <httpProtocol>
      <customHeaders>
        <add name="Access-Control-Expose-Headers " value="WWW-Authenticate"/>
        <add name="Access-Control-Allow-Origin" value="*" />
        <add name="Access-Control-Allow-Methods" value="GET, POST, OPTIONS, PUT, PATCH, DELETE" />
        <add name="Access-Control-Allow-Headers" value="accept, authorization, Content-Type" />
        <remove name="X-Powered-By" />
      </customHeaders>
    </httpProtocol>

    <handlers>
      <remove name="WebDAV" />
      <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
      <remove name="TRACEVerbHandler" />
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
    </handlers>
</system.webServer>

0
//In the Application_OnBeginRequest method in GLOBAL.ASX add the following:-  

var res = HttpContext.Current.Response;  
var req = HttpContext.Current.Request;  
res.AppendHeader("Access-Control-Allow-Origin", "*");  
res.AppendHeader("Access-Control-Allow-Credentials", "true");  
res.AppendHeader("Access-Control-Allow-Headers", "Authorization");  
res.AppendHeader("Access-Control-Allow-Methods", "POST,GET,PUT,PATCH,DELETE,OPTIONS");  

    // ==== Respond to the OPTIONS verb =====
    if (req.HttpMethod == "OPTIONS")
    {
        res.StatusCode = 200;
        res.End();
    }

//Remove any entries in the custom headers as this will throw an error that there's to  
//many values in the header.  

<httpProtocol>
    <customHeaders>
    </customHeaders>
</httpProtocol>
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.