folks.
I have a servive running on my host machine. It is a NodeJS app with Express. It works fine at "localhost:3000".
Then, in a separate project, I have a Laravel App running fine inside Docker, and I access it at "http://localhost".
Now, my Laravel app needs to call the NodeJS app. I saw in Docker documentation I should use "host.docker.internal", since it will resolve to my host machine.
The this->http
is a Guzzle\Client
instance.
In my PHP code I have this:
$response = $this->http->request('POST', env($store->remote), [
'form_params' => [
'login' => $customer->login,
'password' => $customer->password,
]);
If I call the NodeJS app from Postman it works fine. But calling from that PHP I got this error:
"message": "Client error: `POST http://host.docker.internal:3000` resulted in a `404 Not Found` response:\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<title>Error</title>\n</head>\n<body>\n<pre>Cannot POST /</p (truncated...)\n",
"exception": "GuzzleHttp\\Exception\\ClientException",
"file": "/var/www/html/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php",
"line": 113,
Does anyone have any clue how I can call my node app from PHP in Docker?
EDIT
I was thinking if I should not open the port 80 and bind it to port 3000 in my PHP instance (since the request is running in php docker image). I put in my Docker file these ports attribute:
php:
build: ./docker
volumes:
- .:/var/www/html
- ./.env:/var/www/html/.env
- ./docker/config/php.ini:/usr/local/etc/php/php.ini
- ./docker/config/php-fpm.conf:/usr/local/etc/php/php-fpm.conf
- ./docker/config/xdebug.ini:/usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
links:
- mysql
ports:
- "3000:80"
So, port 80 in my PHP instance would bind to my OSX port 3000. But Docker complains port 3000 is in use:
Cannot start service php: b'driver failed programming external connectivity on endpoint project_php_1 (241090....): Error starting userland proxy: Bind for 0.0.0.0:3000 failed: port is already allocated'
Yes! In fact it is allocated. It is allocated by my NodeJS app, that is where I want to go. It looks like I do not know very well how ports and DNS works inside Docker for Mac.
Any help is very appreciated.
SOLVED
Hey, guys. I figured it out. I turned off Docker container, point a regular Apache to my Laravel project and I got what was happening: CORS.
I already had cors
in my Express app, but after configure it better, it worked!
Here it is, in case anyone stumbled here and needs it:
1) Add cors to your Express (if you haven't yet)
2) Configure cors to your domains. For now, I will keep it open, but, for production APPS, please, take care and control wisely who can query your app:
// Express app:
app.use(
cors({
"origin": "*",
"methods": "GET,HEAD,PUT,PATCH,POST,DELETE",
"preflightContinue": false,
"optionsSuccessStatus": 204
})
);
app.options('*', cors());
3) Use the host.docker.internal
address (in my case, host.docker.internal:3000
, since my app is running on that port) from PHP to get to your Express App in OSX host machine. In my case, it will be a different domain/IP when it gets to production.
4) Just use Guzzle\Client
to make your http call:
$response = $this->http->request('POST', env($store->remote) . '/store-api/customers/login', [
'json' => [
"login" => $customer->login,
"password" => encrypt($customer->password),
]
]);
A important point to note: Express waits for json
(in my app, at least), so do NOT use "form_data", use "json" option to POST requests:
At least, it was NOT a duplication of the other answers, as marked by @Phil, because those answers points to the same solution I have already mentioned, use the 'host.docker.internal' address.