Запрос jQuery CORS умирает при предварительном запросе OPTIONS в FireFox

Я не могу сказать, где происходит сбой, будь то проблема jQuery или проблема Compojure или что-то еще.

Я хотел бы сделать этот междоменный запрос:

function signup() {

var signup_username = $('#signup_username').val(); 
var signup_password_1 = $('#signup_password_1').val(); 
var signup_password_2 = $('#signup_password_2').val(); 

$.ajax({
    type: "POST",
    contentType: "application/json",
    url: "http://localhost:40000/signup",
data: 
    JSON.stringify({
        "signup_username": signup_username,
        "signup_password_1": signup_password_1,
        "signup_password_2": signup_password_2
    }),

    complete: function (data) { console.log(data); alert("Done. Look at the console.log to see the results.");  },
    success: function (data) { console.log(data);  },
    error:  function (data) { console.log(data); },
    dataType: "json"
});
}

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

(defroutes app-routes
  (GET "/" request (login-form request))
  (POST "/" request (login request))
  (OPTIONS "/" request (preflight request))
  (GET "/signup" request (signup-form request))
  (POST "/signup" request (signup request))
  (OPTIONS "/signup" request (preflight request))
  (route/resources "/")
  (route/not-found "Page not found. Check the http verb that you used (GET, POST, PUT, DELETE) and make sure you put a collection name in the URL, and possibly also a document ID."))

Я тестирую на своем локальном компьютере, но я хочу протестировать междоменное взаимодействие, поэтому я запускаю одно и то же приложение на двух разных портах: 34001 и 40000. Я укажу FireFox на 34001, а затем Javascript должен выполнить междоменный вызов. до 40000.

Сначала я тестирую это с помощью CURL:

curl -X OPTIONS --verbose  http://localhost:40000/signup

дает мне:

* About to connect() to localhost port 40000 (#0)
*   Trying ::1... connected
* Connected to localhost (::1) port 40000 (#0)
> OPTIONS /signup HTTP/1.1
> User-Agent: curl/7.21.4 (universal-apple-darwin11.0) libcurl/7.21.4 OpenSSL/0.9.8x zlib/1.2.5
> Host: localhost:40000
> Accept: */*
> 
< HTTP/1.1 200 OK
< Date: Sun, 13 Jul 2014 20:43:43 GMT
< Access-Control-Allow-Origin: localhost:40000
< Access-Control-Allow-Methods: PUT, DELETE, POST, GET, OPTIONS, XMODIFY
< Access-Control-Max-Age: 2520
< Access-Control-Allow-Credentials: true
< Access-Control-Request-Headers: x-requested-with, content-type, origin, accept
< Access-Control-Allow-Headers: x-requested-with, content-type, origin, accept
< Content-Type: application/json;charset=ISO-8859-1
< Content-Length: 12
< Server: Jetty(7.x.y-SNAPSHOT)
< 
* Connection #0 to host localhost left intact
* Closing connection #0

Так что я вижу большинство заголовков, которые я ожидал увидеть.

Теперь я тестирую его с FireFox, с включенным Firebug. Firebug не показывает никаких предварительных запросов OPTIONS, вместо этого я просто вижу ошибку:

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:40000/signup. This can be fixed by moving the resource to the same domain or enabling CORS.

Странный. Я должен задаться вопросом, делает ли FireFox предварительный запрос OPTIONS. Итак, я запускаю Charles http://www.charlesproxy.com/

Чарльз показывает мне активность, которую FireBug не показывает. Чарльз показывает мне этот запрос:

OPTIONS /signup HTTP/1.1
Host: localhost:40000
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:30.0) Gecko/20100101 Firefox/30.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://localhost:34001
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache

и Чарльз показывает мне этот ответ:

HTTP/1.1 200 OK
Date: Sun, 13 Jul 2014 20:35:27 GMT
Access-Control-Allow-Origin: http://localhost:34001
Access-Control-Allow-Methods: DELETE, GET, POST, PUT
Content-Type: application/octet-stream;charset=ISO-8859-1
Content-Length: 18
Server: Jetty(7.x.y-SNAPSHOT)

preflight complete

По крайней мере, одна из проблем, с которыми я сталкиваюсь, заключается в том, откуда пришел этот ответ? Как вы можете видеть из моих маршрутов Compojure выше, этот запрос должен был перейти к функции «preflight», которую я определил следующим образом:

(defn preflight [request]
  "2014-07-13 - this is meant to enable CORS so our frontenders can do cross-browser requests. The browser should do a 'preflight' OPTIONS request to get permission to do other requests."
  (print " IN PREFLIGHT ")
  (println " headers host is: " (str (get-in request [:headers "host"])))
  (assoc
      (ring.util.response/response "CORS enabled")
    :headers {"Content-Type" "application/json"
              "Access-Control-Allow-Origin" (str (get-in request [:headers "host"]))
              "Access-Control-Allow-Methods" "PUT, DELETE, POST, GET, OPTIONS, XMODIFY" 
              "Access-Control-Max-Age" "2520"
              "Access-Control-Allow-Credentials" "true"
              "Access-Control-Request-Headers" "x-requested-with, content-type, origin, accept"
              "Access-Control-Allow-Headers" "x-requested-with, content-type, origin, accept"}))

Я вижу эти заголовки, когда тестировал это с помощью CURL, но не когда использую FireFox. А также мои операторы printlin выводятся на терминал, когда я использую CURL, но не FireFox.

По какой-то причине предварительный запрос от FireFox не проходит в мою функцию предварительной проверки. Я не могу понять, куда он идет, на самом деле. Ответ, который он получает, не соответствует ни одному маршруту, который я определил.

У кого-нибудь есть идеи, что происходит?

Я заметил, что этот парень старался изо всех сил и решил, что CORS непригоден для использования:

http://chstrongjavablog.blogspot.com/2013/04/enabling-cors-for-jetty.html

ОБНОВИТЬ:

это выглядит подозрительно:

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

Как сказать «приложение/json»?

Как получить контроль над предварительным запросом, который делает FireFox? Или это jQuery делает это?

Кроме того, этот ответ выглядит очень ограниченным:

Content-Type: application/octet-stream;charset=ISO-8859-1

Опять же, я не могу понять, что вызывает этот возврат, поэтому у меня нет большого контроля над ответом.

Когда я тестирую это в Chrome, я получаю эту ошибку:

 XMLHttpRequest cannot load http://localhost:40000/signup. Request header field Content-Type is not allowed by Access-Control-Allow-Headers. 

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

Если я сделаю это:

curl -X OPTIONS --verbose  http://localhost:40000/signup

Я получаю эти заголовки ответов:

< HTTP/1.1 200 OK
< Date: Sun, 13 Jul 2014 22:45:00 GMT
< Access-Control-Allow-Origin: localhost:40000
< Access-Control-Allow-Methods: PUT, DELETE, POST, GET, OPTIONS, XMODIFY
< Access-Control-Max-Age: 2520
< Access-Control-Allow-Credentials: true
< Access-Control-Allow-Headers: x-requested-with, content-type, origin, accept
< Content-Type: application/json;charset=ISO-8859-1
< Content-Length: 12
< Server: Jetty(7.x.y-SNAPSHOT)

Это включает в себя Access-Control-Allow-Headers, который имеет «тип контента». Но и в Chrome, и в FireFox браузеры выполняют предварительный вызов OPTIONS, который получает ответ, который, похоже, не исходит ни от одного из заданных мною маршрутов.

Если я использую сетевой отладчик Charles, я вижу, что FireFox отправляет следующие заголовки:

OPTIONS /signup HTTP/1.1
Host: localhost:40000
Access-Control-Request-Method: POST
Origin: http://localhost:34001
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.131 Safari/537.36
Access-Control-Request-Headers: accept, content-type
Accept: */*
Referer: http://localhost:34001/signup
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8

и получить этот ответ:

HTTP/1.1 200 OK
Date: Sun, 13 Jul 2014 22:42:58 GMT
Access-Control-Allow-Origin: http://localhost:34001
Access-Control-Allow-Methods: DELETE, GET, POST, PUT
Content-Type: application/octet-stream;charset=ISO-8859-1
Content-Length: 18
Server: Jetty(7.x.y-SNAPSHOT)

preflight complete

Я понятия не имею, откуда такой ответ. Если я сделаю это для всего моего проекта:

grep -iR "preflight complete" *

Фраза «предварительная проверка завершена» не появляется, где мой код. Так откуда такой ответ? И почему FireFox и Chrome не оказываются на том же маршруте, что и при звонке в CURL?

ОБНОВЛЕНИЕ: я наконец нашел ответ.

Я несколько часов метался, пытаясь заставить работать CORS, и среди многих других экспериментов я применил это промежуточное ПО:

https://github.com/r0man/ring-cors

и это отменяло заголовки, которые я отправлял обратно. Мне любопытно, почему это переопределение произошло только для запросов Ajax, а не для запросов curl. Может быть, это какой-то магический r0man, вложенный в кольца. В любом случае, я удалил его и теперь вижу заголовки, которые отправляю обратно.


person cerhovice    schedule 13.07.2014    source источник


Ответы (1)