Axios API request from React Native frontend to local spring backend service not working - reactjs

I develop a React Native mobile app and for the backend I want to use Java Spring.
Now I have a standalone backend server running locally on port 8080 and my react native app is runned via Expo Go app with npm start.
For this question I have built a very simple example.
In the frontend application I want to do a GET request to retrieve a string back from the backend and I am using axios to send API requests.
The problem is that I get a Network Error error whenever I send the GET request to http://localhost:8080/
// dont bother func name
const loginUser = () => {
axios.get("http://localhost:8080/").then(value => {
console.log(value)
}).catch(err => {
console.log("REQUEST FAILED")
console.log(err)
})}
This is the handler when user presses a button axios request is send, Expected output: "Hello World"
output:
REQUEST FAILED
Network Error
at node_modules\axios\lib\core\createError.js:17:22 in createError
at node_modules\axios\lib\adapters\xhr.js:120:6 in handleError
at node_modules\event-target-shim\dist\event-target-shim.js:818:20 in EventTarget.prototype.dispatchEvent
at node_modules\react-native\Libraries\Network\XMLHttpRequest.js:600:10 in setReadyState
at node_modules\react-native\Libraries\Network\XMLHttpRequest.js:395:6 in __didCompleteResponse
at node_modules\react-native\Libraries\vendor\emitter\EventEmitter.js:189:10 in emit
at node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:416:4 in __callFunction
at node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:109:6 in __guard$argument_0
at node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:364:10 in __guard
at node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:108:4 in callFunctionReturnFlushedQueue
#RestController
//#CrossOrigin(origins = "*")
public class TestController {
#GetMapping("/")
public String hello(){
return "Hello World";
}
}
Simple Spring REST Controller
#SpringBootApplication
public class JpaApplication {
public static void main(String[] args) {
SpringApplication.run(JpaApplication.class, args);
}
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedMethods("GET","POST","PUT","DELETE").allowedHeaders("*").allowedOrigins("*");
}
};
}
}
CORS Config just allowing all
I have tried putting the annotation #CrossOrigin(origins = "*") above the controller but it did not help (seen from: React and Axios : Axios Can't Access Java/SpringBoot REST Backend Service Because of CORS Policy). I have allowed all access from all locations in the CORS config but I get the same output. The example is very simple. I just want to get a simple string back and the solution is probably also very simple but after so many tries I can't come up with a solution. If I visit the URL on the browser I get the expected value, but via axios request it does not seem to work.

After some more searching I found it is not possible to send requests directly to localhost on a Android emulator, on IOS there is no problem. So the problem was after all on the React Native side.
So the fix was relatively easy and also found on stackoverflow, the following thread helped a lot: React Native Android Fetch failing on connection to local API.
I Installed ngrok and this generates a URL which I can use to temporary test my backend till I have hosted it.

Related

Spring + ReactJS ERRCONNRESET

i am working on a ReactJS app with a Spring backend server which provides the data. The data is passed via Websockets. Some Snippets from the Spring side of things:
#Autowired
private SimpMessagingTemplate template;
.
.
EditorObject obj = new EditorObject();
template.convertAndSend("/update/editor", obj);
In the ReactJS part the websocket is connected via
const editorSocket = new SockJS("/websocket")
const editorClient = Stomp.over(editorSocket)
editorClient.debug = null
editorClient.connect({}, () => {
console.log("im connect")
editorSubscription = editorClient.subscribe("/update/editor", (msg) => {
// do sth
})
What i am trying to do is work on the project in the development mode via npm start. I added
"proxy": "http://localhost:8080"
to my package.json. Everything works fine in production but when I access the app via npm start on the port 3000 i get the following error in console:
Proxy error: Could not proxy request /websocket/602/m05cnhhq/xhr?t=1675349479939 from localhost:3000 to http://localhost:8080.
See https://nodejs.org/api/errors.html#errors_common_system_errors for more information (ECONNRESET).
Any help is appreciated, having to build to see any changes applied is atrocious.
I have also researched a bit, this seems to be caused by my Spring server cutting the connection. I don't see anything in the server's output that looks anything like that. The only warning i get is
Resolved [org.springframework.http.converter.HttpMessageNotWritableException: No converter for [class java.util.LinkedHashMap] with preset Content-Type 'text/event-stream;charset=UTF-8']

Keycloak CORS issue associated with login redirect

Similar questions here and here have not helped me resolve the problem.
I am using Keycloak 4.4.0 to secure my REST service, which is implemented using Spring Boot and I am using React for the front end.
I get a CORS error when the front end (running on localhost:3000) makes an API call to localhost:8080/login and is redirected to the Keycloak login page.
The error is:
localhost/:1 Failed to load http://localhost:8080/login: Redirect from 'http://localhost:8080/login' to 'http://localhost:9080/auth/realms/hbs/protocol/openid-connect/auth?response_type=code&client_id=hbs&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Flogin&state=ab5034a9-4baa-4be3-9ec1-feefbe5f9c0b&login=true&scope=openid' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access.
I have added a single value of '*' to the Web Origins config section in the Keycloak client.
I have annotated my REST controller as follows:
#RestController
class MyController
{
#CrossOrigin
#GetMapping("/login")
public ResponseEntity<Foo> getFoo(Principal principal)
{
return ResponseEntity.ok(new Foo("blah"));
}
}
I have enabled Keycloak and CORS in the application properties:
keycloak.cors = true
keycloak.enabled = true
If I disable Keycloak and CORS, problem goes away.
As described here, I suspect the issue is to do with the Keycloak server not responding with any Access-Control-Allow-Origin headers despite Web Origins being correctly configured in the Keycloak admin portal. But I'm not completely sure how to confirm this.
Imagine the following json below is your Keycloak configuration:
{
"realm" : "cors",
"resource" : "cors-database-service",
"auth-server-url": "http://localhost-auth:8080/auth",
"bearer-only" : true,
"ssl-required": "external",
"enable-cors": true
}
Try adding the last line to your configuration file.
Let me know if it worked for you!
OBS: I'm facing the same issue, but I'm using Wildfly/JBOSS adapters and making this configuration inside the application server.
#EDIT:
This worked fine for me.
Try changing the "Access Type" to bearer-only inside your REST Client on Keycloak.
Also, don't forget to add the parameter {"{"Authorization" : "bearer " + $TOKEN} when sending HTTP requests from your client to your RESTful API.
For those encountering this error with spring. Just add this class to your project to allow cors:
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
#Configuration
public class CorsConfig implements WebMvcConfigurer {
String[] origins = new String[] { "http://localhost:8081"};
#Override
public void addCorsMappings(CorsRegistry registry) {
System.out.println("TEST TEST");
registry.addMapping("/**")
.allowedOrigins("*");
// .allowedOrigins(origins);
}
}
The asterisk allows all origins, which may not be secure for productive systems. A string array can be used to specify more than one origin.

How to enable Cors in ASP.NET Web Api

I'm learning Angular 2. This is my service that's supposed to pull data from an ASP.NET Web api application.
#Injectable()
export class ExpenseService {
private _expUrl = "http://localhost:65400/api/expenses";
constructor(private _http: Http){}
getExpenses(): Observable<IExpense[]> {
return this._http.get(this._expUrl)
.map((response: Response) => <IExpense[]>response.json())
.do(data => console.log('ALL: ' + JSON.stringify(data)))
.catch(this.handleError)
}
//more here...
}
The above code is working fine in Microsoft Edge. However, in Chrome and FireFox, I'm getting the following error:
XMLHttpRequest cannot load http://localhost:65400/api/expenses.
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'http://localhost:3000' is therefore not allowed
I've enabled CORS in my web api as suggested by many posts.
public void ConfigureServices(IServiceCollection services)
{
services.AddCors();
//...
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env,
ILoggerFactory loggerFactory)
{
//...
app.UseCors(builder =>
builder.WithOrigins("http://localhost:3000/"));
}
That didn't change the outcome. I'm still getting the same error in Chrome and FireFox while Edge is working just fine.
Thanks for helping
CORS is something that are enforced by the client, supported by the server.
CORS is there to help you as a user. It restrict the possibility for a client, like javascript on host google.com, to call a service on mydomain.com. This is a cross-domain call, which Chrome and FireFox does not allow. (Would assume that Edge also supported this). If you are hosting a service and client on some host and port, CORS is not used.
A service must define which host from a cross-domain is allowed. This can either be from all or from a specific host.
To allow access from all host do the following:
Configuration
public void ConfigureServices(IServiceCollection services)
{
services.AddCors();
}
Controller
[EnableCors("AllowSpecificOrigin")]
public class TestController : ApiController
If your service is a public service, be aware of the consequences.
You can read more here: https://learn.microsoft.com/en-us/aspnet/core/security/cors

Angular $http.get call to web api

I have two web applications running. App1 is an angular SPA and App2 is an MVC web api written in c#. I am executing both applications from Visual Studio 2015, running debug in IIS Express.
My angular code (App1) is trying to call an api controller in App2 using the following (debug) code:
$http.get('https://localhost:12345/api/values').then(function (response) {
alert(response.data);
}, function (err) {
alert(err);
}).catch(function (e) {
console.log("error", e);
throw e;
}) .finally(function () {
console.log("This finally block");
});
I always hit the "alert(err);" line - it never successfully executes and err has nothing useful in it to indicate what the problem could be.
In Postman (addin for Chrome), I can confirm the call I'm trying to make to App2 works fine. What am I doing wrong? Could this be an issue with CORS?
Thanks in advance!
You either experiencing CORS/SAME ORIGIN POLICY issue that some information about it in angular js can be found here: How to enable CORS in AngularJs.
this is how you handle it in server site in your case: http://docs.asp.net/projects/mvc/en/latest/security/cors-policy.html#cors-policy
or you better open the developer tools in console tab and bring us some more information about what happened in your code.
Ok the problem I had was in the web api (MVC 6 - ASP.net 5) in that I had to allow the requests from my angular web site. The startup.cs file had the following added:
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc();
services.AddCors();
StartupInitialize(services);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
app.UseIISPlatformHandler();
app.UseStaticFiles();
app.UseCors(builder => builder.WithOrigins("http://localhost:12345/"));
app.UseMvc();
antiForgery = (IAntiforgery)app.ApplicationServices.GetService(typeof(IAntiforgery));
}

Access remote service using GWTP Rest Dispatch

I want to separate packages for UI and backend development of my GWTP app.
Currently my UI access the backend using Rest dispatch configured like this:
bindConstant().annotatedWith(RestApplicationPath.class).to("/MyProject/api");
I want to access remote service using localhost UI (running GWT app using eclipse plugin). I changed the above line to:
bindConstant().annotatedWith(RestApplicationPath.class).to("http://my-app.appspot.com/MyProject/api");
Using this, call successfully reaches server ( I can see this in appengine logs) but UI always gets back status code 0.
What is wrong with above setup? Do I have to do something else to access remote service using GWT ui ?
If you want to have a solution that works both on localhost/App Engine, you'd want to use something like this:
import com.google.gwt.core.client.GWT;
import com.google.gwt.inject.client.AbstractGinModule;
import com.google.inject.Provides;
import com.gwtplatform.dispatch.rest.client.RestApplicationPath;
import com.gwtplatform.dispatch.rest.client.gin.RestDispatchAsyncModule;
public class ServiceModule extends AbstractGinModule {
#Override
protected void configure() {
install(new RestDispatchAsyncModule.Builder().build());
}
#Provides
#RestApplicationPath
String getApplicationPath() {
String baseUrl = GWT.getHostPageBaseURL();
if (baseUrl.endsWith("/")) {
baseUrl = baseUrl.substring(0, baseUrl.length() - 1);
}
return baseUrl + "/MyProject/api";
}
}
The string returned by getApplicationPath will be bound to #RestApplicationPath and used seamlessly by GWTP's RestDispatch.
In your case, the string will resolve to http://localhost:8080/MyProject/api or "http://my-app.appspot.com/MyProject/api" depending on the app running locally or on App Engine.

Resources