【问题标题】:How to overcome "Access-Control-Allow-Origin" error when client talks to server客户端与服务器对话时如何克服“Access-Control-Allow-Origin”错误
【发布时间】:2015-12-16 00:33:37
【问题描述】:

所以我正在使用来自 swiip 的一个名为 generator-gulp-angular 的 yeoman 项目 - 只需执行“npm search gulp-angular”,您就会看到它。

开箱即用的客户端从 127.0.0.1:3000 运行,我希望对 127.0.0.1:8080 上的 (python) 服务进行 $http 调用。它使用浏览器同步进行实时重新加载和代理中间件来进行从客户端到服务器的代理调用。代理中间件默认是禁用的,所以诀窍是启用它并成功地向服务器发出请求并接收来自服务器的响应。到目前为止,我无法成功启用它:-(

更新:我按照“给自己一个简单的例子”的座右铭重新创建了 yeoman 项目,以便专注于访问控制问题,我让它或多或少地开箱即用,而无需修改服务器逻辑以允许跨源请求。令人高兴的是,它就像说明描述的那样简单。这是扩展 gulp 中间件以执行代理的代理文件,或者更确切地说是从客户端映射到服务器:

 /*jshint unused:false */

/***************

  This file proxy.js allows you to configure a proxy system plugged into BrowserSync
  in order to redirect backend requests while still serving and watching
  files from the web project

  IMPORTANT: The proxy is disabled by default.

  If you want to enable it, watch at the configuration options and finally
  change the `module.exports` at the end of the file

***************/

'use strict';

var proxyMiddleware = require('http-proxy-middleware');

var options = {
  target: 'http://127.0.0.1:8080'
};

var proxy = proxyMiddleware('/quote', options);

module.exports = function(){
  return [proxy];
}

从 gulpfile (gulpfile.js) 我们有:

'use strict';

var gulp = require('gulp');
var browserSync = require('browser-sync');
var browserSyncSpa = require('browser-sync-spa');

var util = require('util');

var middleware = require('./proxy');

module.exports = function(options) {

  function browserSyncInit(baseDir, browser) {
    browser = browser === undefined ? 'default' : browser;

    var routes = null;
    if(baseDir === options.src || (util.isArray(baseDir) && baseDir.indexOf(options.src) !== -1)) {
      routes = {
        '/bower_components': 'bower_components'
      };
    }

    var server = {
      baseDir: baseDir,
      routes: routes
    };

    
    // 
    // Here's the relevant bit
    //
    server.middleware = middleware();

    browserSync.instance = browserSync.init({
      startPath: '/',
      server: server,
      browser: browser
    });
  }

  browserSync.use(browserSyncSpa({
    selector: '[ng-app]'// Only needed for angular apps
  }));

  gulp.task('serve', ['watch'], function () {
    browserSyncInit([options.tmp + '/serve', options.src]);
  });

  ..
  
  gulp.task('serve:e2e-dist', ['build'], function () {
    browserSyncInit(options.dist, []);
  });
};

如您所见,我们正在配置 gulp 以了解在客户端 (http://localhost:3000/quote) 上使用时将映射到后端 (http://localhost:8080/quote) 的“/quote”上下文 - 更多信息:@987654323 @

这里是我们使用 $http 服务在客户端上调用的地方:

function quotePriceGenerator($q, $http) {
  var lowPrice = 1.45000, highPrice = 1.47000;
  var askPrice, sellPrice;
  var service = {};
  service.getPrice = function() {
    var deferred = $q.defer();
    $http({
      url: '/quote',
      method: 'GET'
    })
    .then(function(quote) {
      var date = new Date();
      const quoteZoom = 100000;
      const quotePipsWindow = -3;
      ..
      qBox['trading-size-string'] = qBox['trading-size'].toString();
      service.qBox = qBox;
      return deferred.resolve(service);
    });
    // Returns a random integer between min (included) and max (included)
    // Using Math.round() will give you a non-uniform distribution!
    function getRandomIntInclusive(min, max) {
      return Math.floor(Math.random() * (max - min + 1)) + min;
    }
    return deferred.promise;
  };
  return service;
  ..
  function randomizeAskSell(low, high){

  }
}



quotePriceGenerator.$inject = ['$q', '$http'];
export default quotePriceGenerator;

后端是一个 python tornado REST API,不需要对 Access-Control-Allow-Origin 进行任何配置。这里是:

from __future__ import division
import tornado.ioloop
import pyrestful.rest
import random

from pyrestful import mediatypes
from pyrestful.rest import get

class Quote(object):
  quote_date_time = float
  ..
  sell_price = float
  trading_size = int

class QuoteResource(pyrestful.rest.RestHandler):
  @get(_path="/quote", _produces=mediatypes.APPLICATION_JSON)
  def getQuoteJson(self):
    price_min = random.randint(145000,146000)/100000
    price_max = random.randint(146000,147000)/100000
    ..
    quote.sell_price = sell_price
    quote.trading_size = trading_size
    return quote

if __name__ == "__main__":
  try:
    print("Start the service")
    app = pyrestful.rest.RestService([QuoteResource])
    app.listen(8080)
    tornado.ioloop.IOLoop.instance().start()
  except KeyboardInterrupt:
    print("\nStop the service")

【问题讨论】:

  • 您应该编辑问题以包括您在 8080 上运行的 Python 服务/框架。否则问题太宽泛了。简而言之,您需要将服务器(在 8080 上)的 Access-Control-Allow-Origin 标头更改为可以接受您请求的内容。最简单的是*
  • 原来我不需要按照迈克的建议去做。让我解释一下..

标签: angularjs gulp yeoman same-origin-policy


【解决方案1】:

有关错误请求/响应的一些信息也会有所帮助。

您可以尝试将 changeOrigin 参数设置为 true。这将修改请求的主机头以匹配服务器的主机名。

var proxyMiddleware = require('http-proxy-middleware');

var options = {
  target: 'http://127.0.0.1:8080',
  changeOrigin: true         // <-- changeOrigin
};

如果这不起作用;您可以将Access-Control-Allow-Origin 标头添加到响应中:

var proxyMiddleware = require('http-proxy-middleware');

var options = {
  target: 'http://127.0.0.1:8080',
  onProxyRes: function (proxyRes, req, res) {
    proxyRes.headers['Access-Control-Allow-Origin'] = '*';
  }
};

http-proxy-middleware onProxyRes 选项已添加到 v0.5.0 中,因此如果您仍在使用 v0.0.5,请务必更新它

【讨论】:

  • 感谢 chimurai,很高兴知道 - 唯一需要的参数是上下文和目标 ip,即 proxyMiddleware('/quote', {target: '127.0.0.1:8080'})。无论如何我都会给你答案,因为你的插件帮助了我:-)
  • 再次感谢 chimurai :-) 经过几个小时的努力,我刚刚得到了我的 heroku Web 客户端,可以与我的 python REST API 交谈,也部署在 heroku 上,使用 changeOrigin: true选项设置:-)
  • changeOrigin 选项与原始标头无关的事实让我非常困惑。
【解决方案2】:

您必须设置代理服务器来转发您的请求,设置reverse proxy,或在后端设置CORS 以允许跨域请求。

【讨论】:

  • 感谢 scottseeker,但我需要更多细节 - 特别是与我提到的细节相关 :-)
  • 需要更多关于什么是代理中间件的信息。
猜你喜欢
  • 2017-05-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-17
  • 2023-04-02
  • 2017-05-08
  • 2016-08-01
  • 2016-07-29
相关资源
最近更新 更多