Отправка запроса post Angular с параметром в Rails API
Я не могу полностью интегрировать интерфейс Angular с интерфейсом API Rails. Они работают на разных серверах, поэтому я думаю, что у меня проблемы с CORS.
В моем приложении Angular работает контроллер, который вызывает службу с ресурсом с помощью метода запроса (GET) и сохранения (POST). Запрос (GET) работает нормально, однако сообщение не работает.
Я могу отправить запрос POST на сервер, когда я не посылаю никаких параметров. Вот так:
Контроллер:
$scope.createBusiness = function() {
console.log("Business.name=" + $scope.business.name);
$scope.business = Business.save();
};
Услуги:
.factory('Business',
function($resource){
var businesses =
$resource('http://127.0.0.1\\:3000/:business', {business:'businesses'}, {
query: {method:'GET', isArray: true},
save: {method:'POST', isArray: false}
});
return businesses;
}
);
Однако я хочу опубликовать параметры моей модели, поэтому, когда я пытаюсь отправить что-то, я больше не отправляю запрос POST, а запрос OPTIONS. И я получаю сообщение об ошибке.
Пожалуйста, посмотрите мои данные запроса, когда я отправляю запрос без параметров (запрос POST):
Request URL:http://127.0.0.1:3000/businesses
Request Method:POST
Status Code:200 OK
Request Headersview source
Accept:application/json, text/plain, */*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:es-ES,es;q=0.8
Connection:keep-alive
Content-Length:0
Content-Type:text/plain;charset=UTF-8
Host:127.0.0.1:3000
Origin:http://localhost:1234
Referer:http://localhost:1234/app/index.html
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36
Response Headersview source
Access-Control-Allow-Headers:Origin, X-Requested-With, Content-Type, Accept, Authorization
Access-Control-Allow-Methods:POST, PUT, DELETE, GET, OPTIONS
Access-Control-Allow-Origin:*
Access-Control-Max-Age:1728000
Access-Control-Request-Method:*
Cache-Control:max-age=0, private, must-revalidate
Connection:Keep-Alive
Content-Length:9
Content-Type:application/json; charset=utf-8
Date:Mon, 04 Nov 2013 16:50:33 GMT
Etag:"ccd3d779b6f97e2c24633184cbc8f98c"
Server:WEBrick/1.3.1 (Ruby/2.0.0/2013-06-27)
X-Content-Type-Options:nosniff
X-Frame-Options:SAMEORIGIN
X-Request-Id:e084295e-c7c6-4566-80d1-6e2a8ac2e712
X-Runtime:0.034000
X-Ua-Compatible:chrome=1
X-Xss-Protection:1; mode=block
Я добираюсь до сервера, выполняю метод и получаю ответ! Хорошо.
и, см. мои данные запроса, когда я отправляю запрос WITH (запрос OPTIONS):
Request URL:http://127.0.0.1:3000/businesses
Request Method:OPTIONS
Status Code:404 Not Found
Request Headersview source
Accept:*/*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:es-ES,es;q=0.8
Access-Control-Request-Headers:accept, content-type
Access-Control-Request-Method:POST
Connection:keep-alive
Host:127.0.0.1:3000
Origin:http://localhost:1234
Referer:http://localhost:1234/app/index.html
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36
Response Headersview source
Connection:Keep-Alive
Content-Length:131852
Content-Type:text/html; charset=utf-8
Date:Mon, 04 Nov 2013 16:54:04 GMT
Server:WEBrick/1.3.1 (Ruby/2.0.0/2013-06-27)
X-Request-Id:25705159-fbfb-4830-a0f1-6610fa09b70e
X-Runtime:0.371000
UPDATE
Я забыл добавить свой контроллер при добавлении параметра модели:
$scope.createBusiness = function() {
console.log("Business.name=" + $scope.business.name);
$scope.business = Business.save($scope.business);
};
У меня есть несколько представлений с несколькими формами, поэтому я не хочу публиковать форму, но модель бизнес-объекта, которая у меня есть в области (и я заполнил данные всех форм).
UPDATE
Это мой Rails Application_Controller (конфигурация CORS):
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
# OJOJOOJO: Rober: I have commented this line which is provided by default with rails and added all code below in order to
# add CSRF protection
#protect_from_forgery with: :exception
protect_from_forgery
before_filter :cors_preflight_check
after_filter :cors_set_access_control_headers, :set_csrf_cookie_for_ng
# For all responses in this controller, return the CORS access control headers.
def cors_set_access_control_headers
headers['Access-Control-Allow-Origin'] = '*'
headers['Access-Control-Allow-Methods'] = 'POST, PUT, DELETE, GET, OPTIONS'
headers['Access-Control-Request-Method'] = '*'
headers['Access-Control-Allow-Headers'] = 'Origin, X-Requested-With, Content-Type, Accept, Authorization'
headers['Access-Control-Max-Age'] = "1728000"
end
# If this is a preflight OPTIONS request, then short-circuit the
# request, return only the necessary headers and return an empty
# text/plain.
def cors_preflight_check
if request.method == :options
headers['Access-Control-Allow-Origin'] = '*'
headers['Access-Control-Allow-Methods'] = 'POST, PUT, DELETE, GET, OPTIONS'
headers['Access-Control-Request-Method'] = '*'
headers['Access-Control-Allow-Headers'] = 'Origin, X-Requested-With, Content-Type, Accept, Authorization'
headers['Access-Control-Max-Age'] = '1728000'
render :text => '', :content_type => 'text/plain'
end
end
def set_csrf_cookie_for_ng
cookies['XSRF-TOKEN'] = form_authenticity_token if protect_against_forgery?
end
protected
def verified_request?
super || form_authenticity_token == request.headers['X_XSRF_TOKEN']
end
end
Ответы
Ответ 1
Я, наконец, сделал это работу.
Я объясню всю свою конфигурацию в Angular и Rails 4, как мне бы хотелось ее прочитать.
Angular
-
app.js:
angular.module('myApp', ['myApp.filters', 'myApp.services', 'myApp.directives', 'myApp.controllers', 'myApp.i18n', 'demo']).
config(['$routeProvider', '$httpProvider', function($routeProvider, $httpProvider) {
$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common["X-Requested-With"];
}]);
Примечание. Конечно, вам не нужно включать все мои модули.
Примечание. Вы можете определить столько полей, сколько вам нужно, и с привязкой данных присваивать значения объекту.
Примечание. Все атрибуты, которые необходимо отправить в почтовом запросе. Помимо формы, вы можете назначить некоторые новые атрибуты объекту перед отправкой в Rails API. Мы будем использовать службу с объектом ресурса для отправки запроса POST.
-
В моем сервисе:
.factory( "Бизнес",
function($resource){
var businesses =
$resource('http://127.0.0.1\\:3000/:business', {business:'businesses'}, {
query: {method:'GET', isArray: true},
save: {method:'POST', isArray: false}
});
return businesses;
}
);
Примечание. У меня есть запрос GET, чтобы получить бизнес из базы данных через Rails API и POST.
Rails 4
ВАЖНО
Примечание. Новая запись в соответствии с запросом OPTIONS, который сервер Angular отправит, чтобы предварительно обсудить начало отправки запроса POST.
-
application_controller.rb
class ApplicationController < ActionController::Base
before_filter :set_headers
def index
puts "Do nothing."
render nothing: true
end
def set_headers
puts 'ApplicationController.set_headers'
if request.headers["HTTP_ORIGIN"]
# better way check origin
# if request.headers["HTTP_ORIGIN"] && /^https?:\/\/(.*)\.some\.site\.com$/i.match(request.headers["HTTP_ORIGIN"])
headers['Access-Control-Allow-Origin'] = request.headers["HTTP_ORIGIN"]
headers['Access-Control-Expose-Headers'] = 'ETag'
headers['Access-Control-Allow-Methods'] = 'GET, POST, PATCH, PUT, DELETE, OPTIONS, HEAD'
headers['Access-Control-Allow-Headers'] = '*,x-requested-with,Content-Type,If-Modified-Since,If-None-Match,Auth-User-Token'
headers['Access-Control-Max-Age'] = '86400'
headers['Access-Control-Allow-Credentials'] = 'true'
end
end
end
-
Мой контроллер Rails
def create
puts 'Businesses_controller.create!!!!!'
puts business_params.inspect
# business_type object is recovered from db
businessTypeName = params[:type]
businessType = BusinessType.where(:name => businessTypeName).first
...
end
Примечание: сделайте все, что вам нужно...
Ответ 2
У нас была та же проблема, и мы приняли аналогичный, но, надеюсь, более простой/более быстрый/более гибкий подход.
Быстрое изложение того, что я делал, было использовано для библиотеки ruby "rack-cors" (https://github.com/cyu/rack-cors) для управления всеми CORS заголовки.
Это означает, что мне не нужно было вставлять кучу жесткокодированных заголовков/значений заголовка в мой код.
Большое преимущество для меня состояло в том, что это касается как простых запросов CORS (запрос и ответ GET), так и запрограммированных запросов, которые используют запросы OPTION (запрос и ответ OPTIONS, а затем запрос и ответ POST).
Ниже приведены быстрые шаги, которые я выполнил:
- gem install rack-cors
-
добавить в Gemfile следующее:
gem 'rack-cors', :require => 'rack/cors'
-
запустите "bundle install", который обновит Gemfile.lock
-
изменить config/application.rb, чтобы добавить следующий блок:
config.middleware.insert_before "ActionDispatch::Static", "Rack::Cors", :debug => true, :logger => Rails.logger do
allow do
origins '*'
resource '*',
:headers => :any,
:methods => [:get, :post, :delete, :put, :options],
:max_age => 0
end
end
Теперь в моем случае я просто хотел открыть это для любого хоста, но вы можете быть более ограничительным. Вы также можете ограничить заголовки и методы http.
Подробнее о readme на странице github: https://github.com/cyu/rack-cors
(У автора стойки-корса есть примеры рельсовых приложений под примерами /rails 3 и примеры/rails4)