Reputation: 1269
I'm developing my first front-end app based on React. The aim of this app is to connect to a RESTful API in order to get and post data. The problem is I can't send the token header to pass the security check so the request fails.
I get different errors depend on the browser I use.
This is my main.jsx
import React from 'react';
import ReactDOM from 'react-dom';
import promise from 'es6-promise';
import 'isomorphic-fetch';
promise.polyfill();
class Employee extends React.Component {
constructor(props){
super(props);
this.state = {employees : []};
}
componentWillMount(){
fetch('http://localhost:8080/app/rest/employees',{ method: 'get', headers: {'Access-Control-Allow-Origin': 'http://localhost:8080', 'Content-Type': 'x-www-form-urlencoded', 'token' : '93edf459ba78d13be0e9d21143238f43796de1f6ebbc58b133af7f33b8222676'}})
.then((response) => {
return response.json();
})
.then((downscalings) => {
this.setState({ employees: values });
})
}
update(){
this.setState({name : 'John'});
}
render(){
return <div>
<input type="text" value="aaaa"></input>
<button onClick={this.update}>Set name</button>
</div>
}
}
ReactDOM.render(
<Employee/>,
document.getElementById('container')
);
This is the output log error from the browser:
Failed to load resource: the server responded with a status of 401 (No Autorizado)
index.html:1 Fetch API cannot load http://localhost:8080/app/rest/employees. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access. The response had HTTP status code 401. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
index.html:1 Uncaught (in promise) TypeError: Failed to fetch(…)
This is the net trace:
GET employees
localhost:8080
0 B
OPTIONS employees
401 Not authorized
localhost:8080
37 B
I assume that the headers are not sent so the REST service refuses the request. I also added the CORS header because of the warning. What am I doing wrong?
Upvotes: 0
Views: 3856
Reputation: 1269
I am going to response my own answer. Thanks to @cema-sp for the key to find what was happening.
The problem here was related to the CORS configuration in my Spring project. This Spring project exposes a REST API based on token security. It had two problems:
1-The OPTIONS request was blocked by the security token filter:
I wasn't aware how CORS works. CORS, Cross-Origin Resource Sharing, defines a mechanism to enable client-side cross-origin requests. CORS are widely supported by modern browsers like FireFox, Chrome, Safari, and IE. If you just run my fetch and call the backend, you may notice that the GET request is changed to OPTIONS and there is a GET request waiting (You can see that looking to the image at my initial post). The browser sends an OPTIONS request to the server, and the server needs to send the response with correct headers. So that, you need to add these headers to the OPTIONS request.
In the response you have to include which headers are available to the front-end app. In my case, I added the token header to authenticate the requests. If you are using spring 3.1 you need to create a filter like this:
public class CORSFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
response.addHeader("Access-Control-Allow-Origin", "*");
if (request.getHeader("Access-Control-Request-Method") != null && "OPTIONS".equals(request.getMethod())) {
// CORS "pre-flight" request
response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
response.addHeader("Access-Control-Allow-Headers", "Content-Type, token");
response.addHeader("Access-Control-Max-Age", "1");// 30 min
}
filterChain.doFilter(request, response);
}
}
and then add it to the web.xml
<filter>
<filter-name>cors</filter-name>
<filter-class>es.predictia.dp.web.security.CORSFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>cors</filter-name>
<url-pattern>/rest/*</url-pattern>
</filter-mapping>
if you are using spring 4 check this post https://spring.io/blog/2015/06/08/cors-support-in-spring-framework
2-It was resetting all the responses in order to avoid the jsessionid be injected in the response. Now I remove the set-cookie directly.
Thanks everyone
Upvotes: 2