Currently, I am trying to fetch data after communicating with the backend server through SSR through Next.js and sprinkle it on the page.
However, one problem is that when I run npm run dev locally, getServerSideProps runs well, but when I upload it to a container through Docker-compose, my API for getServerSideProps doesn't work.
const ResultMenu: NextPage<Props> = ({ CategoryData }) => {
...
};
export default ResultMenu;
export const getServerSideProps: GetServerSideProps = async (context) => {
try {
const { menuId } = context.query;
const response = await axios.get<CategoryType[]>(
"http://localhost:8080/category/get/menu",
{
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
},
params: {
menuId: menuId,
},
}
);
const data = response.data;
console.log(data);
return {
props: {
CategoryData: data,
},
};
} catch (err) {
console.log(err);
return {
props: {},
};
}
};
In the frontend container, this error code appears
Error: connect ECONNREFUSED 127.0.0.1:8080
at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1195:16) {
errno: -111,
code: 'ECONNREFUSED',
syscall: 'connect',
address: '127.0.0.1',
port: 8080,
config: {
transitional: {
silentJSONParsing: true,
forcedJSONParsing: true,
clarifyTimeoutError: false
},
adapter: [Function: httpAdapter],
transformRequest: [ [Function: transformRequest] ],
transformResponse: [ [Function: transformResponse] ],
timeout: 0,
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN',
maxContentLength: -1,
maxBodyLength: -1,
validateStatus: [Function: validateStatus],
headers: {
Accept: 'application/json, text/plain, */*',
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
'User-Agent': 'axios/0.26.1'
},
params: { menuId: '1' },
method: 'get',
url: 'http://localhost:8080/category/get/menu',
data: undefined
},
request: <ref *1> Writable {
_writableState: WritableState {
objectMode: false,
highWaterMark: 16384,
finalCalled: false,
needDrain: false,
ending: false,
ended: false,
finished: false,
destroyed: false,
decodeStrings: true,
defaultEncoding: 'utf8',
length: 0,
writing: false,
corked: 0,
sync: true,
bufferProcessing: false,
onwrite: [Function: bound onwrite],
writecb: null,
writelen: 0,
afterWriteTickInfo: null,
buffered: [],
bufferedIndex: 0,
allBuffers: true,
allNoop: true,
pendingcb: 0,
constructed: true,
prefinished: false,
errorEmitted: false,
emitClose: true,
autoDestroy: true,
errored: null,
closed: false,
closeEmitted: false,
[Symbol(kOnFinished)]: []
},
_events: [Object: null prototype] {
response: [Function: handleResponse],
error: [Function: handleRequestError],
socket: [Function: handleRequestSocket]
},
_eventsCount: 3,
_maxListeners: undefined,
_options: {
maxRedirects: 21,
maxBodyLength: 10485760,
protocol: 'http:',
path: '/category/get/menu?menuId=1',
method: 'GET',
headers: [Object],
agent: undefined,
agents: [Object],
auth: undefined,
hostname: 'localhost',
port: '8080',
nativeProtocols: [Object],
pathname: '/category/get/menu',
search: '?menuId=1'
},
_ended: true,
_ending: true,
_redirectCount: 0,
_redirects: [],
_requestBodyLength: 0,
_requestBodyBuffers: [],
_onNativeResponse: [Function (anonymous)],
_currentRequest: ClientRequest {
_events: [Object: null prototype],
_eventsCount: 7,
_maxListeners: undefined,
outputData: [],
outputSize: 0,
writable: true,
destroyed: false,
_last: true,
chunkedEncoding: false,
shouldKeepAlive: false,
maxRequestsOnConnectionReached: false,
_defaultKeepAlive: true,
useChunkedEncodingByDefault: false,
sendDate: false,
_removedConnection: false,
_removedContLen: false,
_removedTE: false,
_contentLength: 0,
_hasBody: true,
_trailer: '',
finished: true,
_headerSent: true,
_closed: false,
socket: [Socket],
_header: 'GET /category/get/menu?menuId=1 HTTP/1.1\r\n' +
'Accept: application/json, text/plain, */*\r\n' +
'Content-Type: application/json\r\n' +
'Access-Control-Allow-Origin: *\r\n' +
'User-Agent: axios/0.26.1\r\n' +
'Host: localhost:8080\r\n' +
'Connection: close\r\n' +
'\r\n',
_keepAliveTimeout: 0,
_onPendingData: [Function: nop],
agent: [Agent],
socketPath: undefined,
method: 'GET',
maxHeaderSize: undefined,
insecureHTTPParser: undefined,
path: '/category/get/menu?menuId=1',
_ended: false,
res: null,
aborted: false,
timeoutCb: null,
upgradeOrConnect: false,
parser: null,
maxHeadersCount: null,
reusedSocket: false,
host: 'localhost',
protocol: 'http:',
_redirectable: [Circular *1],
[Symbol(kCapture)]: false,
[Symbol(kNeedDrain)]: false,
[Symbol(corked)]: 0,
[Symbol(kOutHeaders)]: [Object: null prototype]
},
_currentUrl: 'http://localhost:8080/category/get/menu?menuId=1',
[Symbol(kCapture)]: false
},
response: undefined,
isAxiosError: true,
toJSON: [Function: toJSON]
}
1
undefined
Dockerfile
FROM node:12
ENV PORT 3000
# Create app directory
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
# Installing dependencies
COPY package*.json /usr/src/app/
RUN npm install
# Copying source files
COPY . /usr/src/app
# Building app
RUN npm run build
EXPOSE 3000
# Running the app
CMD "npm" "run" "dev"
docker-compose.yml
version: "3"
services:
frontend:
container_name: frontend
build:
context: ./frontend
dockerfile: Dockerfile
ports:
- "3000:3000"
volumes:
- ./frontend:/usr/src/app
- /usr/src/app/node_modules
- /usr/src/app/.next
networks:
- network-tier
backend:
container_name: backend
build: ./backend
depends_on:
- mysqldb
ports:
- 8080:8080
environment:
spring.datasource.url: "jdbc:mysql://mysqldb:3306/test_db?useSSL=false&useLegacyDatetimeCode=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Seoul&characterEncoding=UTF-8&autoReconnect=true&createDatabaseIfNotExist=true"
volumes:
- ./menu-canvas:/usr/src/backend
networks:
- network-tier
tty: true
mysqldb:
image: mysql:5.7
container_name: mysqldb
environment:
MYSQL_DATABASE: test_db
MYSQL_ROOT_PASSWORD: "0000"
MYSQL_ROOT_HOST: "%"
CHARACTER_SET_SERVER: utf8
command:
[
"--character-set-server=utf8mb4",
"--collation-server=utf8mb4_unicode_ci",
]
volumes:
- ./menu-canvas:/usr/src/db
ports:
- "3306:3306"
networks:
- network-tier
platform: linux/amd64
networks:
network-tier:
external: true
volumes:
menu-canvas:
next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
images: {
domains: ["localhost", "*"],
},
reactStrictMode: true,
};
module.exports = nextConfig;
package.json
{
"name": "frontend",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
...
},
"devDependencies": {
...
},
"proxy": {
"*": {
"target": "http://localhost:8080"
}
}
}
I've been thinking a lot all day, but I don't know how... Help!
When running the getServerSideProps the communication would be container to container. So for these requests, routes to localhost would not work. Instead it would need to be something like backend:8080 (when communicating from the frontend service to the backend service).
The localhost domain would work as expected on the client side requests assuming you were exposing all ports as expected.
When you run this without docker everything works because all services are on localhost. When run via docker-compose they no longer are.
If you really wanted to use localhost instead of the service name you may be able to use a network host https://docs.docker.com/network/host/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With