javascript – CORS的问题.烧瓶< - > AngularJS

前端之家收集整理的这篇文章主要介绍了javascript – CORS的问题.烧瓶< - > AngularJS前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
使用 angularjs客户端应用程序和提供api的烧瓶应用程序启动新项目.我正在使用mongodb作为数据库.我不得不立即排除jsonp,因为我需要能够在不同的端口进行POST.所以我们有localhost:9000用于角度应用程序,localhost:9001用于烧瓶应用程序.

我经历了我的API以及我的角度文件中的CORS所需的更改.见下面的来源.我遇到的第一个问题是,有一个错误,CORS允许标头无法识别Chrome中的localhost.我更新了我的hosts文件,所以我可以使用moneybooks.dev,这适用于我的GET请求而不使用JSONP.

现在,我面临的问题.提交POST请求时,Access-Control-Allow-Origin不允许其声明来源http://moneybooks.dev:9000什么? GET可以通过,但POST被拒绝.我看到请求来到烧瓶,但它返回HTTP 400.我需要帮助使POST请求工作.

另一个可能相关的问题是,在我的GET请求中,有时GET请求根本不会触发.就像在BudgetCtrl中的loadBudget函数一样.在#/ budgetgets / budgetID上,预算名称有时根本不会加载.我检查烧瓶日志,看不到请求.然后我点击刷新,我看到请求,预算名称出现在页面上但是在烧瓶日志中我看到一个错误. [Errno 10053]已建立的连接已被主机中的软件中止.它是一个连接错误,只有在GET请求成功时才会出现在烧瓶日志中.

这些问题是否相关?谁能看到我做错了什么?

app.js

'use strict';

angular.module('MoneybooksApp',['ui.bootstrap','ngResource'])
  .config(['$routeProvider','$httpProvider',function ($routeProvider,$httpProvider) {
    $httpProvider.defaults.useXDomain = true;
    delete $httpProvider.defaults.headers.common['X-Requested-With'];
    $routeProvider
      .when('/',{
        templateUrl: 'views/main.html',controller: 'MainCtrl'
      })
      .otherwise({
        redirectTo: '/'
      });
  }]);

budgets.js

'use strict';

angular.module('MoneybooksApp')
  .config(['$routeProvider',function ($routeProvider) {
    $routeProvider
      .when('/budgets',{
        templateUrl: 'views/budgets-list.html',controller: 'BudgetListCtrl'
      })
      .when('/budgets/:budgetID',{
        templateUrl: 'views/budget.html',controller: 'BudgetCtrl'
      });
  }])
  .controller('BudgetListCtrl',function ($scope,$http,$resource) {
    $scope.budgets = [];

    var init = function () {
      $scope.loadBudgets();
    }

    $scope.loadBudgets = function() {
      $http.get('http://moneybooks.dev:9001/api/budgets')
        .success(function (data) {
          $scope.budgets = data;
        })
        .error(function (data) {
          console.error(data);
        });
    };

    init();
  })
  .controller('BudgetCtrl',$routeParams,$resource) {
    $scope.budget = {};

    var init = function () {
      $scope.loadBudget();
    };

    $scope.loadBudget = function() {
      $http.get('http://moneybooks.dev:9001/api/budgets/'+$routeParams['budgetID'])
        .success(function (data) {
          $scope.budget = data;
        })
        .error(function (data) {
          console.error(data);
        });
    };

    init();
  })
  .controller('TransactionCtrl',$resource) {
    $scope.transactions = [];
    $scope.editing = false;
    $scope.editingID;

    var init = function () {};


    $scope.syncUp = function () {
      $http.post('http://moneybooks.dev:9001/api/budgets/'+$routeParams['budgetID']+'/transactions',{transactions: $scope.transactions});
    };

    $scope.syncDown = function () {
      $http.get('http://moneybooks.dev:9001/api/budgets/'+$$routeParams['budgetID']+'/transactions')
        .success(function (transactions) {
          $scope.transactions = transactions;
        });
    };

    $scope.add = function() {
      $scope.transactions.push({
        amount: $scope.amount,description: $scope.description,datetime: $scope.datetime
      });

      reset();
      $scope.defaultSort();
    };

    $scope.edit = function(index) {
      var transaction = $scope.transactions[index];

      $scope.amount = transaction.amount;
      $scope.description = transaction.description;
      $scope.datetime = transaction.datetime;

      $scope.inserting = false;
      $scope.editing = true;
      $scope.editingID = index;
    };

    $scope.save = function() {
      $scope.transactions[$scope.editingID].amount = $scope.amount;
      $scope.transactions[$scope.editingID].description = $scope.description;
      $scope.transactions[$scope.editingID].datetime = $scope.datetime;

      reset();
      $scope.defaultSort();
    };

    var reset = function() {
      $scope.editing = false;
      $scope.editingID = undefined;

      $scope.amount = '';
      $scope.description = '';
      $scope.datetime = '';
    };

    $scope.cancel = function() {
      reset();
    };


    $scope.remove = function(index) {
      $scope.transactions.splice(index,1);
      if ($scope.editing) {
        reset();
      }
    };

    $scope.defaultSort = function() {
      var sortFunction = function(a,b) {
        var a_date = new Date(a['datetime']);
        var b_date = new Date(b['datetime']);

        if (a['datetime'] === b['datetime']) {
          var x = a['amount'],y = b['amount'];
          return x > y ? -1 : x < y ? 1 : 0;
        } else {
          return a_date - b_date
        }
      };

      $scope.transactions.sort(sortFunction);
    };

    $scope.descriptionSuggestions = function() {
      var suggestions = [];

      return $.map($scope.transactions,function(transaction) {
        if ($.inArray(transaction.description,suggestions) === -1){
          suggestions.push(transaction.description);
          return transaction.description;
        }
      });
    };

    $scope.dateSuggestions = function () {
      var suggestions = [];

      return $.map($scope.transactions,function(transaction) {
        if ($.inArray(transaction.datetime,suggestions) === -1){
          suggestions.push(transaction.datetime);
          return transaction.datetime;
        }
      });
    }

    $scope.getRunningTotal = function(index) {
      var runningTotal = 0;
      var selectedTransactions = $scope.transactions.slice(0,index+1);
      angular.forEach(selectedTransactions,function(transaction,index){
        runningTotal += transaction.amount;
      });
      return runningTotal;
    };

    init();

    $(function(){
      (function($){
        var header = $('#budget-header');
        var budget = $('#budget');
        var pos = header.offset();

        $(window).scroll(function(){
          if ($(this).scrollTop() > pos.top && header.css('position') == 'static') {
            header.css({
              position: 'fixed',width: header.width(),top: 0
            }).addClass('pinned');
            budget.css({
              'margin-top': '+='+header.height()
            });
          } else if ($(this).scrollTop() < pos.top && header.css('position') == 'fixed') {
            header.css({
              position: 'static'
            }).removeClass('pinned');
            budget.css({
              'margin-top': '-='+header.height()
            });
          }
        });
      })(jQuery);
    });
  });

API.py

from flask import Flask,Response,Blueprint,request
from pymongo import MongoClient
from bson.json_util import dumps
from decorators import crossdomain
from bson.objectid import ObjectId

try:
    import json
except ImportError:
    import simplejson as json

class APIEncoder(json.JSONEncoder):
    def default(self,obj):
        if isinstance(obj,objectid.ObjectID):
            return str(obj)

app = Flask(__name__)

client = MongoClient()
db = client['moneybooks']

api = Blueprint('api',__name__,url_prefix="/api")

@api.route('/budgets',methods=['GET','POST','OPTIONS'])
@crossdomain(origin='*','OPTIONS'],headers=['X-Requested-With','Content-Type','Origin'])
def budgets():
    if request.method == "POST":
        budget_id = db.budgets.insert({
            'name': request.form['name']
        })
        budget_json = dumps(db.budgets.find_one({'_id': budget_id}),cls=APIEncoder)

    if request.method == "GET":
        budget_json = dumps(db.budgets.find(),cls=APIEncoder)

    return Response(budget_json,mimetype='application/json')

@api.route('/budgets/<budget_id>','Origin'])
def budget(budget_id):
  budget_json = dumps(db.budgets.find_one({'_id': ObjectId(budget_id)}),cls=APIEncoder)
  return Response(budget_json,mimetype='application/json')

@api.route('/budgets/<budget_id>/transactions','Origin'])
def transactions(budget_id):
    if request.method == "POST":
        db.budgets.update({
            '_id': ObjectId(budget_id)
        },{
            '$set': {
                'transactions': request.form['transactions']
            }
        });
        budget_json = dumps(db.budgets.find_one({'_id': ObjectId(budget_id)}),cls=APIEncoder)

    if request.method == "GET":
        budget_json = dumps(db.budgets.find_one({'_id': ObjectId(budget_id)}).transactions,mimetype='application/json')

app.register_blueprint(api)

if __name__ == '__main__':
    app.config['debug'] = True
    app.config['PROPAGATE_EXCEPTIONS'] = True
    app.run()

decorators.py

from datetime import timedelta
from flask import make_response,request,current_app
from functools import update_wrapper

def crossdomain(origin=None,methods=None,headers=None,max_age=21600,attach_to_all=True,automatic_options=True):
    if methods is not None:
        methods = ','.join(sorted(x.upper() for x in methods))
    if headers is not None and not isinstance(headers,basestring):
        headers = ','.join(x.upper() for x in headers)
    if isinstance(max_age,timedelta):
        max_age = max_age.total_seconds()

    def get_methods():
        if methods is not None:
            return methods

        options_resp = current_app.make_default_options_response()
        return options_resp.headers['allow']

    def decorator(f):
        def wrapped_function(*args,**kwargs):
            if automatic_options and request.method == 'OPTIONS':
                resp = current_app.make_default_options_response()
            else:
                resp = make_response(f(*args,**kwargs))
            if not attach_to_all and request.method != 'OPTIONS':
                return resp

            h = resp.headers
            h['Access-Control-Allow-Origin'] = origin
            h['Access-Control-Allow-Methods'] = get_methods()
            h['Access-Control-Max-Age'] = str(max_age)

            if headers is not None:
                h['Access-Control-Allow-Headers'] = headers
            return resp

        f.provide_automatic_options = False
        f.required_methods = ['OPTIONS']
        return update_wrapper(wrapped_function,f)
    return decorator

编辑

从chrome dev控制台输出.

安慰:

XMLHttpRequest无法加载http://moneybooks.dev:9001/api/budgets/5223e780f58e4d20509b4b8b/transactions. Access-Control-Allow-Origin不允许来源http://moneybooks.dev:9000.

网络

Name: transactions /api/budgets/5223e780f58e4d20509b4b8b
Method: POST
Status: (canceled)
Type: Pending
Initiator: angular.js:9499
Size: 13 B / 0 B
Latency: 21 ms

解决方法

正如@TheSharpieOne指出的那样,CORS错误可能是由Chrome Dev Tools错误导致的红色鲱鱼.如果这是一个真正的CORS问题,那么飞行前的OPTIONS调用应该返回相同的错误.

我相信您的400错误可能来自POST请求的处理程序中的request.form [‘transactions’]. request.form是一个MultiDict数据结构,根据http://werkzeug.pocoo.org/docs/datastructures/#werkzeug.datastructures.MultiDict的文档:

From Werkzeug 0.3 onwards,the KeyError raised by this class is also a subclass of the BadRequest HTTP exception and will render a page for a 400 BAD REQUEST if caught in a catch-all for HTTP exceptions.

我相信如果你检查request.forms.keys()中的’transactions’键,你会发现它不存在.请注意,POST的内容类型是application / json而不是x-www-form-urlencoded.根据http://flask.pocoo.org/docs/api/#flask.Request.get_json的文档,当请求mimetype是application / json时,您将需要使用request.get_json()函数获取请求数据.

猜你在找的JavaScript相关文章