Brak „Kontroli dostępu - Zezwalaj na pochodzenie” - Problem z węzłem / portem Apache

260

utworzyłem mały interfejs API za pomocą Node / Express i próbuję pobrać dane za pomocą Angularjs, ale ponieważ moja strona HTML działa pod apache na localhost: 8888, a API węzła nasłuchuje na porcie 3000, otrzymuję brak kontroli dostępu Allow-Origin ”. Próbowałem używać node-http-proxyApache i Vhosts, ale nie odniosłem dużego sukcesu, zobacz pełny błąd i kod poniżej.

XMLHttpRequest nie może załadować localhost: 3000. Żądany zasób nie zawiera nagłówka „Access-Control-Allow-Origin”. Dlatego „localhost: 8888” pochodzenia nie ma dostępu. ”

// Api Using Node/Express    
var express = require('express');
var app = express();
var contractors = [
    {   
     "id": "1", 
        "name": "Joe Blogg",
        "Weeks": 3,
        "Photo": "1.png"
    }
];

app.use(express.bodyParser());

app.get('/', function(req, res) {
  res.json(contractors);
});
app.listen(process.env.PORT || 3000);
console.log('Server is running on Port 3000')

Kod kątowy

angular.module('contractorsApp', [])
.controller('ContractorsCtrl', function($scope, $http,$routeParams) {

   $http.get('localhost:3000').then(function(response) {
       var data = response.data;
       $scope.contractors = data;
   })

HTML

<body ng-app="contractorsApp">
    <div ng-controller="ContractorsCtrl"> 
        <ul>
            <li ng-repeat="person in contractors">{{person.name}}</li>
        </ul>
    </div>
</body>
użytkownik1336103
źródło

Odpowiedzi:

621

Spróbuj dodać następujące oprogramowanie pośrednie do aplikacji NodeJS / Express (dla Twojej wygody dodałem kilka komentarzy):

// Add headers
app.use(function (req, res, next) {

    // Website you wish to allow to connect
    res.setHeader('Access-Control-Allow-Origin', 'http://localhost:8888');

    // Request methods you wish to allow
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');

    // Request headers you wish to allow
    res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');

    // Set to true if you need the website to include cookies in the requests sent
    // to the API (e.g. in case you use sessions)
    res.setHeader('Access-Control-Allow-Credentials', true);

    // Pass to next layer of middleware
    next();
});

Mam nadzieję, że to pomaga!

jvandemo
źródło
2
Czy możesz pomóc dokładnie określić, dokąd to idzie? Mam następujący kod na swoim serwerze. Czy zaraz potem? var app = wymagają („ekspresowe”) (), serwer = wymagają („http”). createServer (aplikacja), io = wymagają („socket.io”). nasłuchuje (serwer), żądanie = wymaga („żądanie”) , url = wymagają („url”); server.listen (6969); // czy to idzie tutaj? na nowej linii?
Art Geigel
1
@jvandemo czy muszę zmienić app.get ('/', function (req, res) na ... function (req, res, next)?
Sangram Singh
10
Jesteś teraz moją ulubioną osobą. Dziękuję Ci. Czy możemy dodać notatkę, że ten kod musi się zdarzyć, zanim zostaną zdefiniowane trasy dla noobów takich jak ja?
gegillam
1
Jak sprawić, by działało to podczas korzystania z modułu żądania?
Rohit Tigga
2
W moim przypadku nie zadziałało. Nadal pojawia się błąd: „Odpowiedź na żądanie inspekcji wstępnej nie przechodzi kontroli kontroli dostępu: Żądany zasób nie zawiera nagłówka„ Kontrola dostępu - Zezwalaj na pochodzenie ”. Z tego powodu pochodzenie„ abc.xyz.net:212 ”jest niedozwolone dostęp. Odpowiedź miała kod statusu HTTP 500. ”
user1451111,
96

Zaakceptowana odpowiedź jest w porządku, jeśli wolisz coś krótszego, możesz użyć wtyczki o nazwie cors dostępnej dla Express.js

Jest prosty w użyciu, w tym konkretnym przypadku:

var cors = require('cors');

// use it before all route definitions
app.use(cors({origin: 'http://localhost:8888'}));
Fabiano Soriani
źródło
3
Musiałem użyć, {origin: 'null'}aby to działało ... Najwyraźniej moja przeglądarka wysyła nulljako źródło?
Ricardo Cruz,
2
Po co wymyślać koło ponownie. Zawsze opowiadam się za pakietem rozwiązań w porównaniu do fragmentu kodu
Pierre
słodka mała biblioteka, która poradziła sobie z moim przypadkiem użycia różnych metod z różnych źródeł całkiem ładnie ... i mniej zmęczenia kodu dla następnego faceta, który na to spojrzy.
Kyle Baker
6
Dzięki, app.use(cors({origin: '*'}));pracował dla mnie, jak na Ena-Cors .
danialk
2
Sugeruję zajrzeć na stronę npm cors, aby lepiej z niej skorzystać. Wyjaśniło mi to bardzo jasno =).
13013SwagR
30

Innym sposobem jest dodanie nagłówków do trasy:

router.get('/', function(req, res) {
    res.setHeader('Access-Control-Allow-Origin', '*');
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE'); // If needed
    res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type'); // If needed
    res.setHeader('Access-Control-Allow-Credentials', true); // If needed

    res.send('cors problem fixed:)');
});
Asaf Hananel
źródło
8
)buźki pomylił mnie
diEcho
17

Top odpowiedź działało w porządku dla mnie, chyba że muszę whitelist więcej niż jedną domenę.

Również najlepsza odpowiedź cierpi z tego powodu OPTIONS żądanie nie jest obsługiwane przez oprogramowanie pośrednie i nie otrzymujesz go automatycznie.

Domeny z białej listy przechowuję jak allowed_originsw konfiguracji Express i od tego czasu umieszczam poprawną domenę zgodnie z originnagłówkiemAccess-Control-Allow-Origin nie pozwala na określenie więcej niż jednej domeny.

Oto, z czym skończyłem:

var _ = require('underscore');

function allowCrossDomain(req, res, next) {
  res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');

  var origin = req.headers.origin;
  if (_.contains(app.get('allowed_origins'), origin)) {
    res.setHeader('Access-Control-Allow-Origin', origin);
  }

  if (req.method === 'OPTIONS') {
    res.send(200);
  } else {
    next();
  }
}

app.configure(function () {
  app.use(express.logger());
  app.use(express.bodyParser());
  app.use(allowCrossDomain);
});
Dan Abramov
źródło
Czy to to samo „if (app.get („ dozwolone źródła ”). IndexOf (pochodzenie)! == - 1)?”?
Rune Jeppesen,
13

Kod odpowiedzi pozwala tylko na localhost: 8888. Tego kodu nie można wdrożyć w produkcji ani pod inną nazwą serwera i portu.

Aby działał dla wszystkich źródeł, użyj tego zamiast tego:

// Add headers
app.use(function (req, res, next) {

    // Website you wish to allow to connect
    res.setHeader('Access-Control-Allow-Origin', '*');

    // Request methods you wish to allow
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');

    // Request headers you wish to allow
    res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');

    // Set to true if you need the website to include cookies in the requests sent
    // to the API (e.g. in case you use sessions)
    res.setHeader('Access-Control-Allow-Credentials', true);

    // Pass to next layer of middleware
    next();
});
Vicheanak
źródło
2
To mi nie działa! „* nie jest prawidłowym źródłem”. Wygląda na to, że * znak nie jest rozpoznawany jako symbol wieloznaczny.
Francesco
Mi to pasuje. tzn. używając symbolu wieloznacznego „*”. działa zarówno na Chrome, jak i na Safari.
AnBisw
Dzięki;) Działa dobrze
Mauro
9

Zainstaluj zależność cors w swoim projekcie:

npm i --save cors

Dodaj do pliku konfiguracyjnego serwera:

var cors = require('cors');
app.use(cors());

Działa dla mnie z wersją cors 2.8.4.

monikaja
źródło
"cors": "^2.8.5", "express": "^4.16.3",działa dobrze tylko z sugerowaną linią @monikaja. Dzięki!
RamiroIsBack
Umożliwia to wszystkim źródłom / domenom dostęp do aplikacji, czego zwykle nie chcesz robić. Zamiast tego podaj tylko dozwolone domeny.
Lacho Tomov
7

To zadziałało dla mnie.

app.get('/', function (req, res) {

    res.header("Access-Control-Allow-Origin", "*");
    res.send('hello world')
})

Możesz zmienić * w zależności od potrzeb. Mam nadzieję, że to może pomóc.

dmx
źródło
7

Cześć, dzieje się tak, gdy frontend i backend działają na różnych portach. Przeglądarka blokuje odpowiedzi z zaplecza z powodu braku nagłówków CORS. Rozwiązaniem jest dodanie nagłówków CORS do żądania zaplecza. Najprostszym sposobem jest użycie pakietu cors npm.

var express = require('express')
var cors = require('cors')
var app = express()
app.use(cors())

Umożliwi to nagłówki CORS we wszystkich twoich żądaniach. Więcej informacji można znaleźć w dokumentacji corsa

https://www.npmjs.com/package/cors

Karthik
źródło
3
app.all('*', function(req, res,next) {
    /**
     * Response settings
     * @type {Object}
     */
    var responseSettings = {
        "AccessControlAllowOrigin": req.headers.origin,
        "AccessControlAllowHeaders": "Content-Type,X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5,  Date, X-Api-Version, X-File-Name",
        "AccessControlAllowMethods": "POST, GET, PUT, DELETE, OPTIONS",
        "AccessControlAllowCredentials": true
    };

    /**
     * Headers
     */
    res.header("Access-Control-Allow-Credentials", responseSettings.AccessControlAllowCredentials);
    res.header("Access-Control-Allow-Origin",  responseSettings.AccessControlAllowOrigin);
    res.header("Access-Control-Allow-Headers", (req.headers['access-control-request-headers']) ? req.headers['access-control-request-headers'] : "x-requested-with");
    res.header("Access-Control-Allow-Methods", (req.headers['access-control-request-method']) ? req.headers['access-control-request-method'] : responseSettings.AccessControlAllowMethods);

    if ('OPTIONS' == req.method) {
        res.send(200);
    }
    else {
        next();
    }


});
Wiki
źródło
2

Dodaj następujący kod do app.js NODEJ Restful api, aby uniknąć błędu „Access-Control-Allow-Origin” w kątowniku 6 lub innym frameworku

var express = require('express');
var app = express();

var cors = require('cors');
var bodyParser = require('body-parser');

//enables cors
app.use(cors({
  'allowedHeaders': ['sessionId', 'Content-Type'],
  'exposedHeaders': ['sessionId'],
  'origin': '*',
  'methods': 'GET,HEAD,PUT,PATCH,POST,DELETE',
  'preflightContinue': false
}));
Ezhil Arasan
źródło
1

Możesz użyć „$ http.jsonp”

LUB

Poniżej znajduje się obejście dotyczące Chrome do testowania lokalnego

Musisz otworzyć Chrome za pomocą następującego polecenia. (Naciśnij okno + R)

Chrome.exe --allow-file-access-from-files

Uwaga: Twój chrom nie może być otwarty. Po uruchomieniu tego polecenia chrome otworzy się automatycznie.

Jeśli wpisujesz to polecenie w wierszu polecenia, wybierz katalog instalacyjny chrome, a następnie użyj tego polecenia.

Poniżej kod skryptu dla otwartego chrome w MAC z „--allow-file-access-from-files”

set chromePath to POSIX path of "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" 
set switch to " --allow-file-access-from-files"
do shell script (quoted form of chromePath) & switch & " > /dev/null 2>&1 &"

drugie opcje

Możesz po prostu użyć open (1), aby dodać flagi: open -a „Google Chrome” --args --allow-file-access-from-files

JQuery Guru
źródło
Co powiesz na MAC? Chrome.exe --allow-file-access-from-files
user1336103
/ Aplikacje / Google \ Chrome.app/Contents/MacOS/Google \ Chrome --allow-file-access-from-files udaje się otworzyć Chrome, ale komunikat nadal pokazuje „XMLHttpRequest nie może załadować localhost: 3000. Pochodzenie localhost: 8888 to niedozwolone przez Access-Control-Allow-Origin. ”
1336103,
+1 Mogę potwierdzić, że działa z opcją Mac za pomocą „open”. Moja sprawa jest nieco inna, ponieważ po prostu testuję całkowicie pobraną witrynę, która ma dostęp do niektórych lokalnych plików JSON.
gąbka
0

/**
 * Allow cross origin to access our /public directory from any site.
 * Make sure this header option is defined before defining of static path to /public directory
 */
expressApp.use('/public',function(req, res, next) {
    res.setHeader("Access-Control-Allow-Origin", "*");
    // Request headers you wish to allow
    res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
    // Set to true if you need the website to include cookies in the requests sent
    res.setHeader('Access-Control-Allow-Credentials', true);
    // Pass to next layer of middleware
    next();
});


/**
 * Server is about set up. Now track for css/js/images request from the 
 * browser directly. Send static resources from "./public" directory. 
 */
expressApp.use('/public', express.static(path.join(__dirname, 'public')));
If you want to set Access-Control-Allow-Origin to a specific static directory you can set the following.

Luton Datta
źródło