(Браузер-как-клиент) HTTP 405 на $.ajax POST в службу узла

ОБЩАЯ ИНФОРМАЦИЯ

Прежде всего, у меня есть служба Restify, работающая на узле, которая отлично работает, когда я использую HTTP-клиент с графическим интерфейсом. Я только констатирую предыдущее, чтобы подчеркнуть, что это проблема, ориентированная на браузер. И если требуется решение на стороне сервера, оно должно приспосабливаться к браузеру...

Вот стопроцентно работающие HTTP-запросы и ответы с использованием моего веб-сервиса Restify и HTTP-клиента с графическим интерфейсом:

Запрос

POST /appointments HTTP/1.1
Content-Type: application/json
Accept: application/json
Host: localhost:8085
Connection: close
User-Agent: Paw/2.1.1 (Macintosh; OS X/10.10.1) GCDHTTPRequest
Content-Length: 142

{
  "eventName": "Fiesta Forever",
  "time": "Fri Dec 19 2014 15:55:00 GMT-0600 (CST)",
  "phoneNumber": "13125555555"
} 

Ответ-

HTTP/1.1 201 Created
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Max-Age: 1000
Content-Type: application/json
Content-Length: 37
Date: Fri, 19 Dec 2014 23:01:29 GMT
Connection: close

{"message":"Alright Alright Alright"}

И что еще более важно, мой сервер создает будущее задание cron, которое можно увидеть в консоли моего сервера:

Created: Fri Dec 19 2014 14:55:00 GMT-0600 (CST)



ПРОБЛЕМА

Моя проблема в том, что я пытаюсь написать интерфейс браузера для своего сервиса. И я получаю сообщение об ошибке, когда пытаюсь сделать тот же HTTP-запрос с помощью Ajax. Я создал следующую тестовую функцию, которая делает HTTP-запрос:

function testPost() {
    var jsonBody = "{\"eventName\": \"Fiesta Forever\",\"time\": \"Fri Dec 19 2014 14:15:00 GMT-0600 (CST)\",\"phoneNumber\": \"13125555555\"}";

    $.ajax({
        url: 'http://localhost:8085/appointments',
        accepts: 'application/json',
        type: 'POST',
        data: jsonBody,
        contentType: 'application/json',
        crossDomain: true,
        headers: {
         "Access-Control-Allow-Origin":true
           }
    });

}

Затем я загружаю свою страницу, содержащую эту функцию, в свой эмулятор iOS и вызываю функцию из консоли разработчика Safari. Я получаю следующую ошибку:

введите здесь описание изображения

РЕДАКТИРОВАТЬ: после удаления заголовков запроса я получаю: Failed to load resource: the server responded with a status of 406 (Not Acceptable)

КОД СЕРВЕРА

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

//CORS
server.use(function(req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
    res.header("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
    res.header("Access-Control-Max-Age", "1000");
    next();
});

Может ли кто-нибудь помочь мне понять, как сделать междоменный HTTP-запрос с использованием $.ajax, который передает и получает JSON?


person Blake G    schedule 19.12.2014    source источник
comment
Является ли server.use выше всех других обратных вызовов http-запроса? если не переместить его над ним   -  person ryanc1256    schedule 20.12.2014
comment
405 немного странный. Ошибка перекрестного происхождения не такова, это сложно и имеет много причуд. Для 405 я бы сделал console.log() для заголовков и метода в объекте req вашей службы Node, чтобы убедиться, что вы знаете, что сервер пытается обработать.   -  person Jordan Kasper    schedule 20.12.2014
comment
Райан, спасибо за подсказку, но перемещение server.use выше всех остальных не решило проблему. Jakerella, я хотел бы проверить входящие req в службе узла, но я не могу найти точку останова, которая сработала. На самом деле запрос не достигает моей конечной точки /appointments/, поэтому я не могу поставить точку останова там или в обработчике функции.   -  person Blake G    schedule 20.12.2014
comment
Отправка заголовка Access-Control-Allow-Origin с вашим запросом бессмысленна — этот заголовок должен быть отправлен сервером в ответе — поэтому удалите его из вашего запроса AJAX. .   -  person CBroe    schedule 20.12.2014
comment
Спасибо, я думал, что это вполне может быть так.   -  person Blake G    schedule 20.12.2014
comment
CBroe, внесение этого изменения привело к ошибке 406, Progress!?   -  person Blake G    schedule 20.12.2014
comment
406 означает (по определению), что сервер не может обслуживать ответ того типа, который вы запросили через заголовок Accept. Попробуйте удалить accepts: 'application/json' из настроек AJAX — это что-то изменит?   -  person CBroe    schedule 20.12.2014
comment
CBroe, ты решил это. Большое спасибо!   -  person Blake G    schedule 20.12.2014
comment
Хорошо, я подытожу это как ответ.   -  person CBroe    schedule 20.12.2014


Ответы (1)


Во-первых, Access-Control-Allow-Origin — это заголовок response, который должен быть отправлен сервером. Отправка его в виде заголовка request вместе с запросом клиента не только не имеет смысла, но и Кажется, это то, что заставляет сервер отклонять ваш запрос здесь, потому что с Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept он сказал вам, какие заголовки запросов он примет, а Access-Control-Allow-Origin среди них нет.

После этого вы получили 406 Not Acceptable, что означает, что сервер не видел себя способным ответить данными типа контента, который был запрошен через заголовок Accept. Таким образом, удаление accepts: 'application/json' заставляет jQuery больше не сообщать серверу, что вы ожидаете определенный тип контента, а просто «дайте мне все, что у вас есть» — что в данном случае, похоже, удовлетворяет сервер…

… и заставить его отвечать Content-Type: application/json в любом случае, что довольно странно, потому что это должно быть именно то, о чем просил jQuery (и ваш первый запрос через GUI также показал). Я не знаю, делает ли jQuery что-то еще из этой настройки (вы можете попробовать и посмотреть, показывает ли сетевая панель инструментов разработчика вашего браузера что-то не так с заголовками запроса)… но проблема решена, и это главное, верно? :-)

person CBroe    schedule 20.12.2014