Chaque fois que je crée une application Web et que je rencontre un problème avec la SCRO, je commence à préparer du café. Après avoir vissé avec pendant un moment, je parviens à le faire fonctionner mais cette fois ce n'est pas et j'ai besoin d'aide.
Voici le code côté client:
$http({method: 'GET', url: 'http://localhost:3000/api/symbol/junk',
headers:{
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, X-Requested-With',
'X-Random-Shit':'123123123'
}})
.success(function(d){ console.log( "yay" ); })
.error(function(d){ console.log( "nope" ); });
Le côté serveur est un node.js normal avec une application express. J'ai une extension appelée cors et elle est utilisée avec express de cette façon:
var app = express();
app.configure(function(){
app.use(express.bodyParser());
app.use(app.router);
app.use(cors({Origin:"*"}));
});
app.listen(3000);
app.get('/', function(req, res){
res.end("ok");
});
Si je fais
curl -v -H "Origin: https://github.com" http://localhost:3000/
Il revient avec:
* Adding handle: conn: 0x7ff991800000
* Adding handle: send: 0
* Adding handle: recv: 0
* Curl_addHandleToPipeline: length: 1
* - Conn 0 (0x7ff991800000) send_pipe: 1, recv_pipe: 0
* About to connect() to localhost port 3000 (#0)
* Trying ::1...
* Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 3000 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.30.0
> Host: localhost:3000
> Accept: */*
> Origin: https://github.com
>
< HTTP/1.1 200 OK
< X-Powered-By: Express
< Date: Tue, 24 Dec 2013 03:23:40 GMT
< Connection: keep-alive
< Transfer-Encoding: chunked
<
* Connection #0 to Host localhost left intact
ok
Si je lance le code côté client, cela provoque cette erreur:
OPTIONS http://localhost:3000/api/symbol/junk No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8000' is therefore not allowed access. angular.js:7889
XMLHttpRequest cannot load http://localhost:3000/api/symbol/junk. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8000' is therefore not allowed access. localhost/:1
nope
Vérification des en-têtes de Chromes:
Request URL:http://localhost:3000/api/symbol/junk
Request Method:OPTIONS
Status Code:200 OK
Request Headersview source
Accept:*/*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8,es;q=0.6,pt;q=0.4
Access-Control-Request-Headers:access-control-allow-Origin, accept, access-control-allow-methods, access-control-allow-headers, x-random-shit
Access-Control-Request-Method:GET
Cache-Control:max-age=0
Connection:keep-alive
Host:localhost:3000
Origin:http://localhost:8000
Referer:http://localhost:8000/
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36
Response Headersview source
Allow:GET
Connection:keep-alive
Content-Length:3
Content-Type:text/html; charset=utf-8
Date:Tue, 24 Dec 2013 03:27:45 GMT
X-Powered-By:Express
En vérifiant les en-têtes de requête, je constate que ma chaîne de test X-Random-Shit est présente dans les "en-têtes de demande de contrôle d'accès", mais que sa valeur n'y figure pas. De plus, dans ma tête, je m'attendais à voir une ligne pour chacun des en-têtes que je suis en train de définir, pas une goutte.
MISES À JOUR ---
J'ai changé mon interface en jQuery au lieu de Angular et ai créé mon backend comme ceci:
var app = express();
app.configure(function(){
app.use(express.bodyParser());
app.use(app.router);
});
app.all('*', function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header('Access-Control-Allow-Methods', 'OPTIONS,GET,POST,PUT,DELETE');
res.header("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Requested-With");
if ('OPTIONS' == req.method){
return res.send(200);
}
next();
});
app.get('/', function(req, res){
res.end("ok");
});
Maintenant, cela fonctionne avec GET mais pas avec autre chose (PUT, POST ..).
Je verrai si l'un de vous propose une solution. En attendant, jetter le concept RESTful par la fenêtre et tout faire avec GETs.
Je suis nouveau sur AngularJS et je suis tombé sur ce problème de la SCRO, j'ai presque perdu la tête! Heureusement, j'ai trouvé un moyen de résoudre ce problème. Alors voilà ...
Mon problème était, quand j'utilise la ressource AngularJS $ dans l'envoi de requêtes d'API, je reçois ce message d'erreur XMLHttpRequest cannot load http://website.com. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access.
Oui, j'ai déjà ajouté callback = "JSON_CALLBACK" et cela n'a pas fonctionné.
Ce que j’ai fait pour résoudre le problème, au lieu d’utiliser la méthode GET ou de recourir à $ http.get, j’ai utilisé JSONP. Il suffit de remplacer la méthode GET par JSONP et de modifier également le format de réponse de l’API en JSONP.
myApp.factory('myFactory', ['$resource', function($resource) {
return $resource( 'http://website.com/api/:apiMethod',
{ callback: "JSON_CALLBACK", format:'jsonp' },
{
method1: {
method: 'JSONP',
params: {
apiMethod: 'hello world'
}
},
method2: {
method: 'JSONP',
params: {
apiMethod: 'hey ho!'
}
}
} );
}]);
J'espère que quelqu'un trouvera cela utile. :)
J'ai eu du succès avec express et en éditant le res.header
. Le mien correspond très bien au vôtre, mais j'ai un Allow-Headers
Différent, comme indiqué ci-dessous:
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
J'utilise aussi Angular et Node/Express, mais les en-têtes ne sont pas appelés dans le code Angular, mais uniquement dans le nœud/express.
Ecrire ce middleware pourrait aider!
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
pour plus de détails, visitez http://enable-cors.org/server_expressjs.html
@ Swapnil Niwane
J'ai pu résoudre ce problème en appelant une requête ajax et en formatant les données en 'jsonp'.
$.ajax({
method: 'GET',
url: url,
defaultHeaders: {
'Content-Type': 'application/json',
"Access-Control-Allow-Origin": "*",
'Accept': 'application/json'
},
dataType: 'jsonp',
success: function (response) {
console.log("success ");
console.log(response);
},
error: function (xhr) {
console.log("error ");
console.log(xhr);
}
});
Ajout ci-dessous à server.js résolu le mien
server.post('/your-rest-endpt/*', function(req,res){
console.log('');
console.log('req.url: '+req.url);
console.log('req.headers: ');
console.dir(req.headers);
console.log('req.body: ');
console.dir(req.body);
var options = {
Host: 'restAPI-IP' + ':' + '8080'
, protocol: 'http'
, pathname: 'your-rest-endpt/'
};
console.log('options: ');
console.dir(options);
var reqUrl = url.format(options);
console.log("Forward URL: "+reqUrl);
var parsedUrl = url.parse(req.url, true);
console.log('parsedUrl: ');
console.dir(parsedUrl);
var queryParams = parsedUrl.query;
var path = parsedUrl.path;
var substr = path.substring(path.lastIndexOf("rest/"));
console.log('substr: ');
console.dir(substr);
reqUrl += substr;
console.log("Final Forward URL: "+reqUrl);
var newHeaders = {
};
//Deep-copy it, clone it, but not point to me in shallow way...
for (var headerKey in req.headers) {
newHeaders[headerKey] = req.headers[headerKey];
};
var newBody = (req.body == null || req.body == undefined ? {} : req.body);
if (newHeaders['Content-type'] == null
|| newHeaders['Content-type'] == undefined) {
newHeaders['Content-type'] = 'application/json';
newBody = JSON.stringify(newBody);
}
var requestOptions = {
headers: {
'Content-type': 'application/json'
}
,body: newBody
,method: 'POST'
};
console.log("server.js : routes to URL : "+ reqUrl);
request(reqUrl, requestOptions, function(error, response, body){
if(error) {
console.log('The error from Tomcat is --> ' + error.toString());
console.dir(error);
//return false;
}
if (response.statusCode != null
&& response.statusCode != undefined
&& response.headers != null
&& response.headers != undefined) {
res.writeHead(response.statusCode, response.headers);
} else {
//404 Not Found
res.writeHead(404);
}
if (body != null
&& body != undefined) {
res.write(body);
}
res.end();
});
});
J'ai trouvé un moyen d'utiliser la méthode JSONP
dans $http
directement et avec le support de params
dans l’objet config:
params = {
'a': b,
'callback': 'JSON_CALLBACK'
};
$http({
url: url,
method: 'JSONP',
params: params
})