1

I know that this subject seems to be already answered many time but i really don't understand it.

  • I have an local angular-fullstack app (Express, NodeJs) which has his server A (localhost:9000/).
  • i have an another local front app B (BlurAdmin done with generator-gulp-angular) (localhost:3000/)

My server A was autogenerate with Express and Nodejs:

  app.use(function (req, res, next) {

    res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000');
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
    res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
    res.setHeader('Access-Control-Allow-Credentials', false);
    next();
});

In my app B, a GET request to my API of serveur A works

$http.get('http://localhost:9000/api/shows')

But with a PUT request:

$http.put('http://localhost:9000/api/shows/1', object)

i have the following error:

XMLHttpRequest cannot load http://localhost:9000/api/shows/1. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. The response had HTTP status code 403.

I try with:

  $http({
    method: "PUT",
    url:'http://localhost:9000/api/shows/1',
    headers: {
      'Content-type': 'application/json'
    },
    data:object
  });

Not working,

I try with:

res.header('Access-Control-Allow-Origin', '*');

Not working,

I have installed *ExtensionAllow-Control-Allow-Origin: ** for chrome and that has done nothing (that return just not all the code but only error 403 (forbidden)

I don't really know why this is not working for PUT when it's working with GET.

Have you already had this problem? Thanks!

Updated:1 The result in my Browser: for GET

General:
Request URL:http://localhost:9000/api/shows/1
Request Method:OPTIONS
Status Code:200 OK

Request header:
Accept:*/*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:fr-FR,fr;q=0.8,en-US;q=0.6,en;q=0.4,de-DE;q=0.2,de;q=0.2
Access-Control-Request-Headers:content-type
Access-Control-Request-Method:PUT
Connection:keep-alive
Host:localhost:9000
Origin:http://localhost:3000
Referer:http://localhost:3000/

Response header: 
Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:X-Requested-With,content-type
Access-Control-Allow-Methods:GET, POST, OPTIONS, PUT, PATCH, DELETE
Access-Control-Allow-Origin:http://localhost:3000
Allow:GET,HEAD,PUT,PATCH,DELETE
Connection:keep-alive
Content-Length:25
Content-Type:text/html; charset=utf-8

For PUT request:

general:
Request URL:http://localhost:9000/api/shows/1
Request Method:PUT
Status Code:403 Forbidden

Response Header:
Connection:keep-alive
Content-Encoding:gzip
Content-Type:application/json; charset=utf-8
Date:Thu, 25 Aug 2016 16:29:44 GMT
set-cookie:connect.sid=s%3AsVwxxbO-rwLH-1IBZdFzZK1xTStkDUdw.xuvw41CVkFCRK2lHNlowAP9vYMUwoRfHtc4KiLqwlJk; Path=/; HttpOnly
set-cookie:XSRF-TOKEN=toaMLibU5zWu2CK19Dfi5W0k4k%2Fz7PYY%2B9Yeo%3D; Path=/
Strict-Transport-Security:max-age=31536000; includeSubDomains; preload

Request header:
Accept:application/json, text/plain, */*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:fr-FR,fr;q=0.8,en-US;q=0.6,en;q=0.4,de-DE;q=0.2,de;q=0.2
Connection:keep-alive
Content-Length:27
Content-Type:application/json
Host:localhost:9000
Origin:http://localhost:3000
Referer:http://localhost:3000/

Request Payload:
{url_name: "myData"}
url_name
:
"myData"

Thanks for helping

Update 2: with https://github.com/troygoode/node-cors-server/blob/master/app.js and the work of @Chris Foster I have install npm cors --save in my app.js, i have now the following code:

import express from 'express'; 
import cors from 'cors'; 

var app = express()

var corsOptions = {
  origin: 'http://localhost:3000'
}
var issuesoption = {
  origin: true,
  methods: ['PUT'],
  credentials: true,
};


app.use(cors(corsOptions))
app.options('*', cors(issuesoption));
app.put('/api/shows/:id',cors(issuesoption) ,function(req,res){
  res.json({
    data: 'Issue #2 is fixed.'
  });
});

And that is still not working with:

$http.put("http://localhost:9000/api/shows/1",object)

BUT i don't have any 403 error, I have now,

Request URL:http://localhost:9000/api/shows/1
Request Method:PUT
Status Code:200 OK

But that doesn't put the data into the server and i have in Preview:

{data: "Issue #2 is fixed."}
Wandrille
  • 6,267
  • 3
  • 20
  • 43
  • 1
    Did you enable the cors in the plugin(google chrome extension)? – Shankar Shastri Aug 25 '16 at 16:14
  • yes, Enable cross-origin resource sharing is on TRUE, when it is activated, i have only the error: 403 (Forbidden) – Wandrille Aug 25 '16 at 16:17
  • 1
    did u try restarting the browser? – Shankar Shastri Aug 25 '16 at 16:18
  • 1
    Could you include the full list of request headers for the PUT request and GET request, as captured in your browser's Network dev tools? – apsillers Aug 25 '16 at 16:19
  • I have restart the browser, and that is not working. – Wandrille Aug 25 '16 at 16:22
  • I try to update my demand – Wandrille Aug 25 '16 at 16:23
  • 1
    @Wandrille Okay, so if there's no actual POST request, then it's failing on the preflight request. Make sure your server sends appropriate headers for the preflight as well. (GET doesn't require a preflight request.) You may be interested in my answer on [How does Access-Control-Allow-Origin header work?](http://stackoverflow.com/a/10636765/710446) – apsillers Aug 25 '16 at 16:26

1 Answers1

9

When you make a request that can change something (POST, PUT, etc), CORS rules require that the browser makes a preflight request (OPTIONS) before making the actual request.

In Node, you have to specifically handle these OPTION requests. It's likely you are only handling the PUT (app.put('/etc/etc/')), and the preflight request is failing.

You need to add handling for preflight OPTION requests, but better yet check out the cors package which makes this all much more simple and does it for you:

const express = require('express')
const cors = require('cors')

const app = express()

const corsOptions = {
  origin: 'http://example.com'
}

app.use(cors(corsOptions))
Chris Foster
  • 2,639
  • 2
  • 23
  • 30
  • @Wandrille This code does actually solve your problem, the fact that you now see a `200 OK` means the request works :) The JSON that you see in preview is exactly what the route is designed to do: send the JSON to the client. It doesn't do anything with the data you send it because you haven't coded the route to do anything yet. – Chris Foster Aug 25 '16 at 20:13
  • 1
    To "put the data into the server" like you mentioned, that is a different problem. You have to do something with the data the client sends you in the route handler using `req.body` and the `bodyParser` middleware like mentioned in [this question](http://stackoverflow.com/questions/4295782/how-do-you-extract-post-data-in-node-js). If you need more help after that, you should open a new question as it is unrelated to the CORS problem. Good luck! – Chris Foster Aug 25 '16 at 20:15
  • i have tried with only your code but I keep having the problem. Thanks :) – Wandrille Aug 25 '16 at 20:15
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/121868/discussion-between-chris-foster-and-wandrille). – Chris Foster Aug 25 '16 at 20:16
  • Ensure you add this middleware immediately after creating the express app before adding other middlewares, didn't work for me initially until I did this. – Goke Obasa Feb 09 '17 at 00:56