56

I tried a ReactJS fetch call to a REST-API and want to handle the response. The call works, i get a response, which i can see in Chrome Dev Tools:

function getAllCourses() {
fetch('http://localhost:8080/course', {
    method: 'POST',
    mode: 'no-cors',
    credentials: 'same-origin',
    headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json',
    },
    body: JSON.stringify({
        objectClass: 'course',
        crud: '2'
    })
}).then(function (response) {
    console.log(response);
    return response.json();

}).catch(function (err) {
    console.log(err)
});
}

When i try to handle the response, i got a "SyntaxError: Unexpected end of input" at

return response.json();

The console.log looks like this:

Console.log(response)

My Response JSON looks like this, it is valid, i checked it with jsonlint:

[
  {
    "0x1": {
      "users": [],
      "lectures": [],
      "owner": "0x2",
      "title": "WWI 14 SEA",
      "description": null,
      "objectClass": "course",
      "id": "course_00001"
    },
    "0x2": {
      "username": "system",
      "lectures": [],
      "course": null,
      "solutions": [],
      "exercises": [],
      "roles": [
        "0x3",
        "0x4",
        "0x5"
      ],
      "objectClass": "user",
      "id": "user_00001"
    },
    "0x3": {
      "roleName": "ROLE_ADMIN",
      "objectClass": "role",
      "id": "role_00001"
    },
    "0x4": {
      "roleName": "ROLE_STUDENT",
      "objectClass": "role",
      "id": "role_00002"
    },
    "0x5": {
      "roleName": "ROLE_DOCENT",
      "objectClass": "role",
      "id": "role_00003"
    }
  }
]
sideshowbarker
  • 81,827
  • 26
  • 193
  • 197
Chilliggo
  • 605
  • 1
  • 6
  • 9

6 Answers6

109

You need to remove the mode: 'no-cors' setting from your request. Setting no-cors mode is exactly the cause of the problem you’re having.

A no-cors request makes the response type opaque. The log snippet in the question shows that. Opaque means your frontend JavaScript code can’t see the response body or headers.

https://developer.mozilla.org/en-US/docs/Web/API/Request/mode explains:

no-cors — JavaScript may not access any properties of the resulting Response

So the effect of setting no-cors mode is essentially to tell browsers, “Don’t let frontend JavaScript code access the response body or headers under any circumstances.”

People sometimes try setting no-cors mode when a response doesn’t include the Access-Control-Allow-Origin response header or else because the request is one that triggers a CORS preflight, and so your browser does an OPTIONS preflight.

But using no-cors mode isn’t a solution to those problems. The solution is either to:

sideshowbarker
  • 81,827
  • 26
  • 193
  • 197
  • In case of django localhost server install `github.com/ottoyiu/django-cors-headers` then set settings.py `CORS_ORIGIN_ALLOW_ALL = True` for development purposes. – Moreno Mar 30 '18 at 20:10
  • Thanks for the insight @sideshowbarker! In my case, though, even after I removed the `mode` and so it's set to default (`cors` as I'm sending a `Request`), but when the response is `ok: false`, I still get `unexpected end of json input` in Promise – afkatja Apr 25 '19 at 14:29
4

In your then you should check if the response is OK before returning response.json:

.then(function (response) {
    if (!response.ok) {
        return Promise.reject('some reason');
    }

    return response.json();

})

If you want to have the error message in your rejected promise, you can do something like:

.then(function (response) {
    if (!response.ok) {
       return response.text().then(result => Promise.reject(new Error(result)));
    }

    return response.json();
})
Kmaschta
  • 2,369
  • 1
  • 18
  • 36
  • Thank you, but in my case this is not helpful. I want to know why it does not work? Is my JSON not valid? Why is my response not ok? – Chilliggo Apr 10 '17 at 08:30
  • Your request can fail for various reasons, you can use the response API to find out why: https://developer.mozilla.org/en-US/docs/Web/API/Response/Response Log `response.status`, `response.statusText` and so on. The error message will be printed. Your JSON is fine, it is the client which cannot find your server. You can also open the browser console to have a helpful message. – Kmaschta Apr 10 '17 at 08:35
2

I know this answer might be super late and might have been resolved but i just had the same issue today and I just needed to add a ',' at the end of the headers hash and i stopped getting the error

export function addContacts(formData) {
  return(dispatch) => {
    dispatch({type: 'POSTING_CONTACTS'});
    console.log(formData)
    return fetch(uri, {
      method: 'POST',
      body: JSON.stringify({contact: {name: formData.name, phone_number: formData.phoneNumber}}),
      headers: {
        Accept: 'application/json',
        'Content-Type': 'application/json'
      },
    })
    .then(response => {
        return response.json()
      }).then(responseJSON => {
        console.log(responseJSON)
        return dispatch({type: 'ADD_CONTACT', payload: responseJSON});
      })
  }
}     
0

You can avoid the problem with CORS policy by adding in the header of php or another server endpoint the row:

<?php
header('Access-Control-Allow-Origin: *');
//or
header('Access-Control-Allow-Origin: http://example.com');

// Reading JSON POST using PHP
$json = file_get_contents('php://input');
$jsonObj = json_decode($json);

// Use $jsonObj
print_r($jsonObj->message);

...
// End php
?>

Model of working fetch code with POST request is:

const data = {
        optPost: 'myAPI',
        message: 'We make a research of fetch'
    };
const endpoint = 'http://example.com/php/phpGetPost.php';

fetch(endpoint, {
    method: 'POST',
    body: JSON.stringify(data)
})
.then((resp) => resp.json())
.then(function(response) {
    console.info('fetch()', response);
    return response;
});
Roman
  • 19,236
  • 15
  • 93
  • 97
0

This answer is to clarify what is needed in the back end in order to complete a successful CORS request. In this example you see only OPTIONS & POST are allowed from ANY Origination * provided the Authorization header includes a Bearer token sent along with the request. Focus on fetchOptions and defaultResponseHeaders.

SERVER SIDE:

A simple if condition is created to handle OPTIONS http request that inquires about CORS permisions which the browser sends with every request you are making.

const defaultResponseHeaders = new Headers({
  "Server": "JSON-RPC 2.0 Server",
  "Allow": "OPTIONS, POST",
  "Cache-Control": "no-store",
  "Content-Type": "application/json; charset=UTF-8",
  "Content-Language": "en-US",
  "Access-Control-Allow-Origin": "*",
  "Access-Control-Allow-Methods": "OPTIONS, POST",
  "Access-Control-Allow-Headers": "Content-Type, Authorization"
});

if (reqMethod == "OPTIONS") {
  console.info("S: 204 No Content");

  status = 204;
  statusText = "No Content";

  return new Response(null, {
    headers: defaultResponseHeaders,
    status: status,
    statusText: statusText,
  });
}

CLIENT SIDE:

Notice the mode: "cors" inside fetchOptions. This instructs the browser to make an OPTIONS request to the API endpoint which then tells the browser what it will accept via the Access-Control CORS headers you specify in defaultResponseHeaders.

async function getProjectJSON(projectId) {
  
  const rpcRequest = {
    jsonrpc: "2.0",
    method: "readproject_n",
    params: {
      id: projectId
    },
    id: "c990be06-298b-4f00-b822-50f585e69163",
    timestamp: Date.now()
  };

  // fetch options
  const fetchOptions = {
    method: "POST",
    mode: "cors",
    headers: {
      "Content-Type": "application/json",
      "Authorization": "Bearer 29fea2ddebd08ed73a0fe7952968ca60b9e56e678a367578825b6c4c8824d248",
    },
    body: JSON.stringify(rpcRequest)
  };
  // make request
  const request = await fetch(`http://10.0.0.9:3000/jsonrpc`, fetchOptions);
  // parse JSON response
  const response = await request.json();
  // return JS object
  return response;
}
suchislife
  • 4,251
  • 10
  • 47
  • 78
-1

Simply copy the following code and paste it on your web.config file under <system.webServer> tag.

<httpProtocol>  
    <customHeaders>  
     <add name="Access-Control-Allow-Origin" value="*" />  
     <add name="Access-Control-Allow-Headers" value="Content-Type" />  
     <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />  
    </customHeaders>  
  </httpProtocol>  
Juboraj Sarker
  • 947
  • 1
  • 9
  • 13