Получение 404 для запроса CORS к веб-API только в Chrome и только на сервере

Я пытаюсь отправить данные POST с веб-сайта в конечную точку веб-API на том же сервере с тем же доменным именем, но с другим номером порта. Он работает с IE11 как локально, так и на нашем тестовом сервере, но Chrome работает только локально. На тестовом сервере получаю ошибку 404. Насколько я могу судить, он квалифицируется как «простой» запрос, однако ошибка 404 показывает, что HTTP-метод был «ОПЦИИ», поэтому он должен выполнять предварительный запрос и не выполнять его.

zone.js:2933 OPTIONS http://example.com:8001/api/search/quickSearch?v=1.35.2664 404 (Not Found)
scheduleTask @ zone.js:2933
webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.scheduleTask @ zone.js:411
onScheduleTask @ zone.js:301
webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.scheduleTask @ zone.js:405
webpackJsonp.../../../../zone.js/dist/zone.js.Zone.scheduleTask @ zone.js:236
webpackJsonp.../../../../zone.js/dist/zone.js.Zone.scheduleMacroTask @ zone.js:259
(anonymous) @ zone.js:2966
proto.(anonymous function) @ zone.js:1366
(anonymous) @ angular.js:12587
sendReq @ angular.js:12332
serverRequest @ angular.js:12084
processQueue @ angular.js:16832
(anonymous) @ angular.js:16876
$digest @ angular.js:17971
(anonymous) @ static.js:1502
schedulerFn @ core.js:4351
webpackJsonp.../../../../rxjs/_esm5/Subscriber.js.SafeSubscriber.__tryOrUnsub @ Subscriber.js:240
webpackJsonp.../../../../rxjs/_esm5/Subscriber.js.SafeSubscriber.next @ Subscriber.js:187
webpackJsonp.../../../../rxjs/_esm5/Subscriber.js.Subscriber._next @ Subscriber.js:128
webpackJsonp.../../../../rxjs/_esm5/Subscriber.js.Subscriber.next @ Subscriber.js:92
webpackJsonp.../../../../rxjs/_esm5/Subject.js.Subject.next @ Subject.js:56
webpackJsonp.../../../core/esm5/core.js.EventEmitter.emit @ core.js:4319
checkStable @ core.js:4718
onLeave @ core.js:4797
onInvokeTask @ core.js:4747
webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invokeTask @ zone.js:424
webpackJsonp.../../../../zone.js/dist/zone.js.Zone.runTask @ zone.js:192
webpackJsonp.../../../../zone.js/dist/zone.js.ZoneTask.invokeTask @ zone.js:499
ZoneTask.invoke @ zone.js:488
timer @ zone.js:2040
setTimeout (async)
scheduleTask @ zone.js:2056
webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.scheduleTask @ zone.js:411
onScheduleTask @ zone.js:301
webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.scheduleTask @ zone.js:405
webpackJsonp.../../../../zone.js/dist/zone.js.Zone.scheduleTask @ zone.js:236
webpackJsonp.../../../../zone.js/dist/zone.js.Zone.scheduleMacroTask @ zone.js:259
(anonymous) @ zone.js:2072
proto.(anonymous function) @ zone.js:1366
setTimeout @ lodash.js:6663
timerExpired @ lodash.js:10388
webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invokeTask @ zone.js:425
onInvokeTask @ core.js:4744
webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invokeTask @ zone.js:424
webpackJsonp.../../../../zone.js/dist/zone.js.Zone.runTask @ zone.js:192
webpackJsonp.../../../../zone.js/dist/zone.js.ZoneTask.invokeTask @ zone.js:499
ZoneTask.invoke @ zone.js:488
timer @ zone.js:2040
setTimeout (async)
scheduleTask @ zone.js:2056
webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.scheduleTask @ zone.js:411
onScheduleTask @ zone.js:301
webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.scheduleTask @ zone.js:405
webpackJsonp.../../../../zone.js/dist/zone.js.Zone.scheduleTask @ zone.js:236
webpackJsonp.../../../../zone.js/dist/zone.js.Zone.scheduleMacroTask @ zone.js:259
(anonymous) @ zone.js:2072
proto.(anonymous function) @ zone.js:1366
setTimeout @ lodash.js:6663
leadingEdge @ lodash.js:10358
debounced @ lodash.js:10425
fn @ VM445:4
$eval @ angular.js:18161
(anonymous) @ angular.js:25998
(anonymous) @ angular.js:28813
forEach @ angular.js:403
$$writeModelToScope @ angular.js:28811
writeToModelIfNeeded @ angular.js:28804
(anonymous) @ angular.js:28798
validationDone @ angular.js:28723
processAsyncValidators @ angular.js:28706
$$runValidators @ angular.js:28650
$$parseAndValidate @ angular.js:28791
$commitViewValue @ angular.js:28757
(anonymous) @ angular.js:28898
$eval @ angular.js:18161
$apply @ angular.js:18261
$$debounceViewValueCommit @ angular.js:28897
$setViewValue @ angular.js:28875
listener @ angular.js:24822
dispatch @ jquery.js:4737
elemData.handle @ jquery.js:4549
webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invokeTask @ zone.js:425
onInvokeTask @ core.js:4744
webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invokeTask @ zone.js:424
webpackJsonp.../../../../zone.js/dist/zone.js.Zone.runTask @ zone.js:192
webpackJsonp.../../../../zone.js/dist/zone.js.ZoneTask.invokeTask @ zone.js:499
invokeTask @ zone.js:1540
globalZoneAwareCallback @ zone.js:1566
(index):1 Failed to load http://example.com:8001/api/search/quickSearch?v=1.35.2664: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://example.com' is therefore not allowed access. The response had HTTP status code 404.

Вот как выглядит мой Global.asax для включения запросов CORS:

    protected void Application_BeginRequest(object sender, EventArgs e)
    {
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", ConfigurationManager.AppSettings["RootUri"].TrimEnd('/'));
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, HEAD, PUT, DELETE, OPTIONS");
        HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "30");
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Credentials", "true");
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Accept, Accept-CH, Accept-Charset, Accept-Datetime, Accept-Encoding, Accept-Ext, Accept-Features, Accept-Language, Accept-Params, Accept-Ranges, Access-Control-Allow-Credentials, Access-Control-Allow-Headers, Access-Control-Allow-Methods, Access-Control-Allow-Origin, Access-Control-Expose-Headers, Access-Control-Max-Age, Access-Control-Request-Headers, Access-Control-Request-Method, Age, Allow, Alternates, Authentication-Info, Authorization, C-Ext, C-Man, C-Opt, C-PEP, C-PEP-Info, CONNECT, Cache-Control, Compliance, Connection, Content-Base, Content-Disposition, Content-Encoding, Content-ID, Content-Language, Content-Length, Content-Location, Content-MD5, Content-Range, Content-Script-Type, Content-Security-Policy, Content-Style-Type, Content-Transfer-Encoding, Content-Type, Content-Version, Cookie, Cost, DAV, DELETE, DNT, DPR, Date, Default-Style, Delta-Base, Depth, Derived-From, Destination, Differential-ID, Digest, ETag, Expect, Expires, Ext, From, GET, GetProfile, HEAD, HTTP-date, Host, IM, If, If-Match, If-Modified-Since, If-None-Match, If-Range, If-Unmodified-Since, Keep-Alive, Label, Last-Event-ID, Last-Modified, Link, Location, Lock-Token, MIME-Version, Man, Max-Forwards, Media-Range, Message-ID, Meter, Negotiate, Non-Compliance, OPTION, OPTIONS, OWS, Opt, Optional, Ordering-Type, Origin, Overwrite, P3P, PEP, PICS-Label, POST, PUT, Pep-Info, Permanent, Position, Pragma, ProfileObject, Protocol, Protocol-Query, Protocol-Request, Proxy-Authenticate, Proxy-Authentication-Info, Proxy-Authorization, Proxy-Features, Proxy-Instruction, Public, RWS, Range, Referer, Refresh, Resolution-Hint, Resolver-Location, Retry-After, Safe, Sec-Websocket-Extensions, Sec-Websocket-Key, Sec-Websocket-Origin, Sec-Websocket-Protocol, Sec-Websocket-Version, Security-Scheme, Server, Set-Cookie, Set-Cookie2, SetProfile, SoapAction, Status, Status-URI, Strict-Transport-Security, SubOK, Subst, Surrogate-Capability, Surrogate-Control, TCN, TE, TRACE, Timeout, Title, Trailer, Transfer-Encoding, UA-Color, UA-Media, UA-Pixels, UA-Resolution, UA-Windowpixels, URI, Upgrade, User-Agent, Variant-Vary, Vary, Version, Via, Viewport-Width, WWW-Authenticate, Want-Digest, Warning, Width, X-Content-Duration, X-Content-Security-Policy, X-Content-Type-Options, X-CustomHeader, X-DNSPrefetch-Control, X-Forwarded-For, X-Forwarded-Port, X-Forwarded-Proto, X-Frame-Options, X-Modified, X-OTHER, X-PING, X-PINGOTHER, X-Powered-By, X-Requested-With");

        // If a preflight request, end it so we don't fetch data.
        if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
        {
            HttpContext.Current.Response.End();
        }
    }

Почему я получаю 404 и как это исправить?


person adam0101    schedule 15.01.2018    source источник
comment
Вы, вероятно, захотите также включить фрагмент кода, показывающий часть кода JavaScript вашего внешнего интерфейса, которая инициирует запрос. Если бы он на самом деле квалифицировал простой запрос, ваш браузер не отправлял бы эти OPTIONS предварительной проверки. И, несмотря на это, реальная проблема, по-видимому, заключается в том, что сервер, на который отправляется запрос, неправильно настроен для неправильного ответа на запросы OPTIONS с ошибкой 404, и фрагмент кода Global.asax в вопросе, похоже, не решает эту проблему.   -  person sideshowbarker    schedule 16.01.2018


Ответы (1)


Chrome и Safari также могут выполнять предварительные запросы OPTIONS для методов, отличных от GET (например, POST).

Я не уверен, что означает ConfigurationManager.AppSettings["RootUri"].TrimEnd('/') - заголовки ответа ACAO должны быть либо звездочкой, либо (как кажется, вы пытаетесь сделать) полным доменным именем, включая схему и порт (если порт не 80 или 443) - поэтому в вашем случае он должен иметь ТОЧНОЕ значение "http://example.com:8001" . Гораздо проще просто отразить значение заголовка запроса Origin (который будет иметь это значение).

Можете ли вы опубликовать заголовки запроса и ответа?

person roryhewitt    schedule 18.01.2018
comment
У меня похожая проблема, мое приложение создано с использованием Angular 7. Я делаю вызов ajax на сервер BPMS, который отлично работает в IE, но у меня есть ошибка CORS в Chrome. Однако, когда я копирую URL-адрес ajax в браузер Chrome, у меня есть все данные. Кто-нибудь может помочь? - person David Sagang; 18.08.2020