Fetch timeout when port-forwarding from docker container - javascript

I'm working on simple project consisting of two docker containers in docker network (bridge). The issue it that I'm getting timeout from backend when calling it from host (via port-forward to frontend)
Setup:
docker network create --driver bridge my-network
Java Spring backend providing random quotes from database under /randomQuote endpoint
docker run -it --rm --name backend --network my-network backend:1.0
Javascript frontend for displaying the received quote
docker run -it --rm --name frontend --network my-network -p 8081:8081 frontend:1.0
Frontend code for requesting the data (called on button click):
const requestQuote = async() => {
let response = await fetch(apiUrl + getRandomQuoteEndpoint)
if(handleErrors(response)){
quote = await response.json()
displayQuote()
}
}
I tried various versions for apiUrl like:
http://backend:8080
http://172.18.0.2:8080
backend:8080
172.18.0.2:8080
Backend interface:
#RequestMapping("/")
public interface QuotesRestController {
#CrossOrigin()
#GetMapping("/randomQuote")
public ResponseEntity<Quote> getRandomQuote();
}
On host http://localhost:8081/ is displaying frontend content properly but when requesting the quote I'm receiving GET http://172.18.0.2:8080/randomQuote net::ERR_CONNECTION_TIMED_OUT.
curl from frontend is returning the quotes correctly, so issue is only when I'm port-forwarding and trying to display on host.
I suspect that this is because the call to backend:8080/randomQuote is made from my host's browser which is not in docker network so it's not able to reach backend.
Is it an issue with my configuration/code? Or I should use different approach?

Related

HTTP requests in React app are not working over a network connection, but they are working on localhost

I’ve been building a React app for a while now and have been testing responsiveness across multiple devices.
The React app itself works perfectly fine on my local machine. When accessing the React instance over the network, all HTTP requests fail because it wants to send HTTP requests to port 3000 instead of port 5000 which is what my Node.js server is running on.
[1] Compiled successfully!
[1]
[1] You can now view client in the browser.
[1]
[1] Local: http://localhost:3000
[1] On Your Network: http://192.168.1.122:3000
[0] [nodemon] starting `node server.js`
[1] Compiled successfully!
[1] webpack compiled successfully
[0] Server is running on port 5000
[0] MongoDB Connected!
Example of a request in the React app
// Submit application to database
const storeAndSubmit = (formData) => {
try {
// eslint-disable-next-line
const res = axios({
method: 'post',
headers: {
'Content-Type': 'application/json',
},
url: 'http://localhost:5000/api/applications',
data: formData,
});
dispatch({
type: APPLICATION_SUCCESS,
payload: formData.pageNumber,
});
} catch (err) {
dispatch({
type: APPLICATION_FAIL,
});
}
};
Because I don’t know what IP address React will choose when running my start script, I can’t just hard code the IP address into the request. Is there a React environment variable that can be accessed that has the current local network IP address after the start script has been run? If so, I can use that in my HTTP requests and I think that might work.
Error example over the network
xhr.js:210 POST http://192.168.1.122:3000/api/applications 404 (Not Found)
One thing you can do is proxy your requests by adding the following to your package.json file: "proxy": "http://localhost:5000",
Now in your fetch or Axios calls you can use the following URL '/api/applications' instead of 'http://localhost:5000/api/applications'
You are having a networking issue, so let’s go over it in detail.
You have two processes running on your development machine:
a Node.js HTTP server serving the HTML file which loads the React app on localhost:3000. Let’s call this AppServerProcess
a Node.js HTTP server running a controller/driver for the database on localhost:5000. Let’s call this DbServerProcess
So what happens when you are requesting the web application from another device in the network?
The device will make an HTTP request to http://192.168.1.122:3000, where the AppServerProcess will handle the request and respond with the HTML content and the relevant scripts and assets, which will be loaded by the browser. The code in the JavaScript scripts (the web application), will have the fetch code with a URI of http://localhost:5000, which the device will resolve into itself, where it will fail to find anything.
Now, the computer running both processes (DbServerProcess and AppServerProcess) has at least one IP address on the local network, which is 192.168.1.122. This means that if the DbServerProcess is running on localhost:5000, it should also be available on 192.168.1.122:5000, so the URI that should be hardcoded on fetch is http://192.168.1.122:5000/api/applications.
Note that this will also work when working locally, as the IP address will resolve to itself.
Also note that if the computer running both processes has DHCP configured, this IP address may change subject to that configuration, where you seem to have a misconception of what is happening, because it’s not React that chooses that, and it’s not even the AppServerProcess; it’s the OS which has at least one network interface that has a local IP address assigned by the DHCP server running on the router. If you want this to be static, then that is an OS configuration (pretty straight forward on both Windows, macOS and Linux).
Look for "setting static IP address on {operating_system_name}".
I will assume if you specify the React port while starting your app, you will be able to solve this issue and correct me if I am wrong.
You can just do this on Linux:
PORT=3006 react-scripts start
Or this on Windows:
set PORT=3006 && react-scripts start
Check this answer.
Look into cors-npm for your backend server because that maybe the reason for not connecting.
Later you can maybe use Cloudflare Tunnel for your web server and use that address to access your web server in the react app. The link can be provided as an environment variable for the react. see setup react env variable
Firstly, test if the backend API is working or not via Postman.
http://192.168.1.122:5000/ should work on your case.
=========================================================
After it
Try this code on your frontend after checking the backend is working correctly with Postman.
const api = axios.create({
baseURL: "http://192.168.1.122:5000/api/", //PLEASE CONFIRM IP.
headers: {
'Content-Type': 'application/json',
},
});
const submitApi = async (formData) => api.post('/applications', formData);
const storeAndSubmit = async (formData) => {
try {
const {data} = await submitApi(formData);
if(!!data) {
dispatch({
type: APPLICATION_SUCCESS,
payload: formData.pageNumber,
});
} else {
dispatch({
type: APPLICATION_FAIL,
});
}
} catch(e) {
dispatch({
type: APPLICATION_FAIL,
});
}
}
I think you should check the response on the browser in the device you want to connect to the app from.
With the 404 code, the potential reason may be that the device and your computer are not using the same Wi-Fi modem.
You should not use a domain at all:
url: '/api/applications',
or
url: 'api/applications',
The former dictates api to be served from the domain's root, and the latter requires api to be served from the current page's path. In both cases, schema, domain, and port will be inherited from the current page's URL.
Details are in RFC 2396.
It allows you use your code without changes on any domain, any port, as the hosting architecture is not of the frontend app's concern.
Make a .env file and maybe try this:
REACT_APP_API_ENDPOINT=http://192.168.1.blablabla
You can also do:
"scripts" : {
"start": "REACT_APP_API_ENDPOINT=http://localhost.whatever npm/yarn start"
"start-production": "REACT_APP_API_ENDPOINT=http://production.whatever npm/yarn start"
}
It was taken from How can I pass a custom server hostname using React?.

Build succeeded for heroku app but running into "Application Error"

When I checked the Heroku build logs, it showed this:
The requested API endpoint was not found. Are you using the right HTTP verb (i.e. GET vs. POST), and did you specify your intended version with the Accept header?
My app runs on React framework for front end, and I use the Firebase realtime database for my backend. The app runs fine on my local server but when I try to deploy on to Heroku I run into this error.
My guess is that you didn't set the environment variables, thus the base url for your request might be invalid. You can set them in Settings tab of your heroku application, under the Config Vars section.

How can I execute functions in a node.js file hosted by Heroku from a file hosted in a different environment?

I currently use host winds to host a html/css/js files. I need to use Node for a new project aspect, and host winds says id have to use a virtual private server. so I figured ill use Heroku, since I have experience deploying to that environment already.
the heroku application has to execute a stripe operation:
(dummy data)
const stripe = require('stripe')('sk_test_NOFBwvYmIyZln2c64bv84A');
stripe.oauth.token({
grant_type: 'authorization_code',
code: 'ac_123456789',
}).then(function(response) {
// asynchronously called
var connected_account_id = response.stripe_user_id;
});
followed by a firebase firestore write operation
How can I connect to the heroku environment from a file hosted on Hostwinds? Is it as simple as creating an express server in the node.js heroku deployment, and calling a fetch POST/GET to an express endpoint from the web page thats hosted by host winds
Is it as simple as creating an express server in the node.js heroku deployment, and calling a fetch POST/GET to an express endpoint from the web page thats hosted by host winds
Exactly, call one of the routes in your app on heroku servers and then run your function from there.

proxy not working for create-react-app in production

I am working with reactjs(create-react-app) to create a dashboard application, In my application i am calling multiple host (for that I have configured multiple proxies in package.json to avoid CORS).
ex- www.app.demo1.com, www.app.demo2.com, www.app.demo3.com...
"proxy": {
"/demo1/api/":{
"target":"www.app.demo1.com"
},
"/demo2/api/":{
"target":"www.app.demo2.com"
},
"/demo3/api/":{
"target":"www.app.demo3.com"
}
}
in application i am calling like-
try{
const host1 = process.env.NODE_ENV === 'production'?
'www.app.demo1.com/demo1/api': '/demo1/api/';
const host2 = process.env.NODE_ENV === 'production'?
'www.app.demo2.com/demo2/api': '/demo2/api/';
const host3 = process.env.NODE_ENV === 'production'?
'www.app.demo3.com/demo3/api': '/demo3/api/';
const resp1 = axios.get(host1)
const resp2 = axios.get(host2)
const resp3 = axios.get(host3)
}catch(){}
in development: when making request to /demo1/api/ it is being proxied to
www.app.demo1.com/demo1/api and i am getting the response. but
in production: I have deployed the application on github pages, although I am getting the below error,
enter image description here
Can anybody help..
Proxies are for development purposes only, and they are handled by webpack-dev-server. On production you need to make the calls to the actual host.
This is created because usually, on development, react is served by a standalone server meant just for that (hence, webpack-dev-server). On production, usually there is a backend (node? ruby? php?) that serves the pages and every call made is going to be to some endpoint with the same hostname.
Example:
In your development environment you have a node server running on port 3001 and your react code running on port 3000. When react fetches /api/user, you actually want http://localhost:3001/api/user, which points to your node server.
In your production environment, you have a server (nginx, maybe?) that forwards all /api calls to your node process, and for everything else it serves your react main index.html file (so you can use react-router, for example). In this case, whenever you request /api/user, this is going to be handled by your web server and routed properly.

Why can't web app in docker-compose, connect to another container in the same compose?

I have a docker compose file with at least 2 tomcat containers:
(Heads up, this is not a valid docker-compose, only a template)
version: "3"
services:
restapidependencies:
xxxxxx
restapi:
image: tomcat:8.0-jre8
depends_on:
- restapidependencies
ports:
- "8888:80"
command: catalina.sh run
web:
image: tomcat:8.0-jre8
depends_on:
- coreservices
ports:
- "7777:80"
command: catalina.sh run
One is a RESTful api and the other is a web app built on javascript (angularJS). There are an X numbers of other services that restapi depends on, (database, redis, etc). The rest api connects successfully to its dependencies using the name of the service defined in docker-compose.yaml, however, the application inside the web service cannot connect to the restapi service. That said, when I docker exec into the web container, I can successfully make request to the restapi using curl.
Is there a know scenario where a javascript application wouldn't be able to connect to a docker container in the same docker-compose.
PS: I did not develop the app running web so I have limited knowledge of anything special it may be doing, my front end developer gave me an explanation around the lines: "The web app is running inside the browser", which makes sense.
Some thoughts: Does that means web apps don't have access to localhost either? Even if that is the case, docker compose creates a network of containers so no localhost is shared in the same app, technically web is calling a completely different ip, not localhost.
i docker exec into the web container, I can successfully make request to the restapi using curl
Then your restapi is accessible from your web container. So it looks like a wrong configuration.
Is there any log message?
How does the app tries to bring up the connection?
Maybe you forgot to define any environment variables for your webapp?
Maybe your rest api doesn't exposes any port?
Try to get a log output that tells you why the connection fails.

Categories