-->

How to overcome “Access-Control-Allow-Origin” erro

2020-04-21 07:49发布

问题:

So I'm using a yeoman project from swiip called generator-gulp-angular - just do "npm search gulp-angular" and you'll see it.

Out of the box the client is running from 127.0.0.1:3000 and I wish to make a $http call to a (python) service on 127.0.0.1:8080. Its using browser-sync for live reload and proxy middleware to make the proxy calls from client to server. Proxy middleware is per default disabled, so the trick is to enable it and successfully make requests to and receive responses from server. So far i've not been able to successfully enable it :-(

Update: I recreated the yeoman project following the motto "give yourself a simple example" in order to concentrate on the Access-Control issue and I got it to work more or less out of the box without having to resort to modifying the server logic in order to allow cross origin requests. Pleasingly it's as simple as the instructions describe. Here's the proxy file that extends the gulp middleware to perform the proxy, or rather mapping from client to server:

 /*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];
}

From the gulpfile (gulpfile.js) we have:

'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, []);
  });
};

As you see we're configuring gulp to be aware of the "/quote" context that when used on the client (http://localhost:3000/quote) will get mapped to the backend (http://localhost:8080/quote) - for further information: https://github.com/chimurai/http-proxy-middleware/blob/v0.0.5/README.md

Here's where we make the call on the client using the $http service:

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;

The backend, a python tornado REST API, didn't require any configuration for Access-Control-Allow-Origin. Here it is:

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")

回答1:

Some information on the erroneous request/response would be helpful too.

You could try to set the changeOrigin param to true. This will modify the request's host header to match the server's hostname.

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

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

If that doesn't work; you can add the Access-Control-Allow-Origin header to the response:

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 option is added in v0.5.0 , so make sure to update it if you're still using v0.0.5



回答2:

You have to setup a proxy server to forward your requests, setup a reverse proxy, or setup CORS on the back-end to allow the cross-origin request.