Результат вызова jQuery AJAX в статусе ошибки 403

Я делаю запрос к веб-службе с помощью jQuery AJAX. Мой запрос выглядит так:

var serviceEndpoint = 'http://example.com/object/details?version=1.1';
$.ajax({
  type: 'GET', 
  url: serviceEndpoint,
  dataType: 'jsonp',
  contentType: 'jsonp',
  headers: { 'api-key':'myKey' },
  success: onSuccess,
  error: onFailure
});

Когда я выполняю это, я получаю сообщение об ошибке 403. Я не понимаю, почему мой вызов приводит к статусу кода 403. Я контролирую безопасность своей службы и отмечен как широко открытая, Я знаю, что ключ действителен, потому что я использую его в другом вызове, который работает. Вот вызов, который работает:

var endpoint = 'http://example.com/object/data/item?version=1.1';
$.ajax({ 
  type: 'POST', 
  url: endpoint, 
  cache: 'false',
  contentType:'application/json',
  headers: {
    'api-key':'myKey',
    'Content-Type':'application/json'
  },
  data: JSON.stringify({
    id: 5,
    count:true
  }),
  success: onDataSuccess,
  error: onDataFailure
});

Я знаю, что это две разные конечные точки. Но я на 100% убежден, что это не аутентификация на сервере или ошибка разрешения. И снова все открыто на стороне сервера. Это подразумевает, что я делаю ошибку на своем клиентском запросе.

Я чувствую, что должен сообщить, что этот запрос делается во время разработки. Итак, я запускаю это из http://localhost:3000. По этой причине я сразу же предположил, что это проблема CORS. Но все выглядит правильно. Тот факт, что мой запрос POST работает, но мой GET не делает меня абсолютно расстроенным. Я что-то упускаю? Что это может быть?

Ответ 1

Причиной ошибки 403 является то, что вы не отправляете заголовки. Поскольку вы делаете запрос CORS, вы не можете отправлять какие-либо пользовательские заголовки, если сервер не включает эти заголовки, добавляя Access-Control-Allow-Headers к ответу.

В предварительном запросе клиент делает 2 запроса к серверу. Первый - предпечатная проверка (с методом OPTIONS), а второй - реальный запрос. Сервер отправляет заголовок Access-Control-Allow-Headers в качестве ответа на запрос предварительной проверки. Таким образом, он позволяет отправлять некоторые заголовки. Таким образом, ваш запрос POST может работать, потому что запрос POST является предварительным запросом. Но для запроса GET нет предварительной проверки для сбора заголовка Access-Control-Allow-Headers, и браузер не отправляет ваши пользовательские заголовки в этом случае.

Обходной путь для этой проблемы:

В качестве обходного пути установите для ваших dataType и contentType значение json следующим образом:

var serviceEndpoint = 'http://example.com/object/details?version=1.1';
$.ajax({
  type: 'GET', 
  url: serviceEndpoint,
  dataType: 'json',
  contentType: 'json',
  headers: { 'api-key':'myKey' },
  success: onSuccess,
  error: onFailure
});

Таким образом, ваш запрос на получение будет preflighted request. Если ваш сервер активирует api-key с заголовком Access-Control-Allow-Headers, он будет работать.

Пример конфигурации сервера для вышеуказанного запроса (записан в express.js):

res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', '*');
res.setHeader('Access-Control-Allow-Headers', 'api-key,content-type');
res.setHeader('Access-Control-Allow-Credentials', true);

ДОБАВЛЕНО:

На самом деле, contentType должен быть либо application/javascript либо application/json при выполнении запроса jsonp. Там нет contentType как jsonp.

Ответ 2

Если вы посмотрите на страницу API для вызова jQuery Ajax, в разделе Content-Type будет указано следующее:

Примечание.. Для междоменных запросов настройка типа содержимого на что угодно кроме приложений /x -www-form-urlencoded, multipart/form-data или text/plain приведет браузер к отправке предполетных опций запрос на сервер.

Эта страница на самом деле не упоминает, что такое "предполетный запрос OPTIONS", но я нашел некоторые интересные ссылки при просмотре этой фразы в Интернете:

Что представляет собой пример кода и Изображение CORS на странице HTML5Rocks. На изображении показано, как вызовы Ajax выполняются из кода JavaScript в браузер на сервер и как ответы округляются между всеми тремя из них.

Мы склонны думать о JavaScript + Browser = Client, но на иллюстрации автор объясняет разницу между кодом веб-разработчика и кодом разработчика браузера, где первый написан в коде JavaScript, но последний был написан с использованием C, С++ или С#.

Хороший инструмент анализатора пакетов Fiddler, который будет похож на Wireshark. Любой из этих инструментов должен показывать вам запросы перед полетом, которые отправляются из браузера на сервер. Скорее всего, там, где ваш запрос Ajax блокируется сервером с 403 Запрещенная ошибка.