월 17,600원
5개월 할부 시다른 수강생들이 자주 물어보는 질문이 궁금하신가요?
- 해결됨[리뉴얼] React로 NodeBird SNS 만들기
_app.js 특정페이지에 적용하고싶지 않을때
_app.js 를 적용하면 모든페이지에 적용된다 했는데 특정페이지만 _app.js 를 적용하고싶지 않으면 어떻게 해야되나요?
- 미해결[리뉴얼] React로 NodeBird SNS 만들기
새로고침후 content
안녕하세요, 제로초님 영상강의 잘 따라가면서 문제없이 진행하다가 서버 재시작하거나 새로고침하면 2번째 사진처럼 돌아가는데 routes/post.js에서 게시글 로드할때 데이터를 다시 가공해야하는 건가요?..
- 해결됨[리뉴얼] React로 NodeBird SNS 만들기
eslint 적용 후 에러...
이게 대체 무슨 에러인지 모르겠습니다... 검색도해보고에러메시지에서시킨대로도해봤는데 아무리해도없어지지가않아요ㅠㅜ 도와주십숑..
- 미해결[리뉴얼] React로 NodeBird SNS 만들기
https 적용후 nginx 502 bad gateway 오류
안녕하세요, 제로초님. 배포 후 nginx가 502 bad gateway 오류가 발생했는데, 어제는 잘 되다가 오늘 갑자기 안되서 질문드립니다... 서버를 AWS lightsail을 이용하였고, nginx/letsencrypt를 사용하여 https를 적용하였습니다. nginx 부분은 블로그에 작성하신 내용을 참고하였고, default와 .conf 파일 은 다음과 같습니다. //etc/nginx/nginx.conf user www-data; worker_processes auto; pid /run/nginx.pid; include /etc/nginx/modules-enabled/*.conf; events { worker_connections 768; # multi_accept on; } http { sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 2048; include /etc/nginx/mime.types; default_type application/octet-stream; ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE ssl_prefer_server_ciphers on; access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; gzip on; include /etc/nginx/conf.d/*.conf; include /etc/nginx/sites-enabled/*; } /etc/nginx/sites-enabled/default server { listen 443 ssl; server_name apis.hometownalba.com; ssl_certificate /etc/letsencrypt/live/apis.hometownalba.com/fullchain.pem; # managed b y Certbot ssl_certificate_key /etc/letsencrypt/live/apis.hometownalba.com/privkey.pem; # managed by Certbot include /etc/letsencrypt/options-ssl-nginx.conf; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; location / { proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; user www-data; user www-data; } server { listen 443 ssl; server_name apis.hometownalba.com; ssl_certificate /etc/letsencrypt/live/apis.hometownalba.com/fullchain.pem; # managed by Certbot ssl_certificate_key /etc/letsencrypt/live/apis.hometownalba.com/privkey.pem; # managed by Certbot include /etc/letsencrypt/options-ssl-nginx.conf; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; location / { proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header X-Real-IP $remote_addr; proxy_pass http://127.0.0.1:3065; proxy_redirect off; proxy_connect_timeout 300; proxy_send_timeout 300; proxy_read_timeout 300; } } 그리고 error log를 찍어보았는데, 다음과 같았습니다. 2021/11/10 05:36:35 [error] 1603#1603: *5 upstream prematurely closed connection while reading response header from upstream, client: 1.238.158.106, server: apis.hometownalba.com, request: "GET / HTTP/1.1", upstream: "http://127.0.0.1:3065/", host: "apis.hometownalba.com" 2021/11/10 05:39:37 [error] 1684#1684: *5 upstream prematurely closed connection while reading response header from upstream, client: 1.238.158.106, server: apis.hometownalba.com, request: "GET / HTTP/1.1", upstream: "http://127.0.0.1:3065/", host: "apis.hometownalba.com" 매번 답변 감사드립니다 ㅠㅠ
- 미해결[리뉴얼] React로 NodeBird SNS 만들기
디버깅
[제로초 강좌 질문 필독 사항입니다]질문에는 여러분에게 도움이 되는 질문과 도움이 되지 않는 질문이 있습니다.도움이 되는 질문을 하는 방법을 알려드립니다.https://www.youtube.com/watch?v=PUKOWrOuC0c0. 숫자 0부터 시작한 이유는 1보다 더 중요한 것이기 때문입니다. 에러가 났을 때 해결을 하는 게 중요한 게 아닙니다. 왜 여러분은 해결을 못 하고 저는 해결을 하는지, 어디서 힌트를 얻은 것이고 어떻게 해결한 건지 그걸 알아가셔야 합니다. 그렇지 못한 질문은 무의미한 질문입니다.1. 에러 메시지를 올리기 전에 반드시 스스로 번역을 해야 합니다. 번역기 요즘 잘 되어 있습니다. 에러 메시지가 에러 해결 단서의 90%를 차지합니다. 한글로 번역만 해도 대부분 풀립니다. 그냥 에러메시지를 올리고(심지어 안 올리는 분도 있습니다. 저는 독심술사가 아닙니다) 해결해달라고 하시면 아무런 도움이 안 됩니다.2. 에러 메시지를 잘라서 올리지 않아야 합니다. 입문자일수록 에러메시지에서 어떤 부분이 가장 중요한 부분인지 모르실 겁니다. 그러니 통째로 올리셔야 합니다.3. 코드도 같이 올려주세요. 다만 코드 전체를 다 올리거나, 깃헙 주소만 띡 던지지는 마세요. 여러분이 "가장" 의심스럽다고 생각하는 코드를 올려주세요.4. 이 강좌를 바탕으로 여러분이 응용을 해보다가 막히는 부분, 여러 개의 선택지 중에서 조언이 필요한 부분, 제 경험이 궁금한 부분에 대한 질문은 대환영입니다. 다만 여러분의 회사 일은 질문하지 마세요.5. 강좌 하나 끝날 때마다 남의 질문들을 읽어보세요. 여러분이 곧 만나게 될 에러들입니다.6. 위에 적은 내용을 명심하지 않으시면 백날 강좌를 봐도(제 강좌가 아니더라도) 실력이 늘지 않고 그냥 코딩쇼 관람 및 한컴타자연습을 한 셈이 될 겁니다. 디버깅하는데 자꾸 오류가 나서 찾아봤는데 해결방법을 모르겠어요..
- 미해결[리뉴얼] React로 NodeBird SNS 만들기
갑자기 궁금한게 생겻는데용
실무에서는 dispatch를 두가지 방법중 어떤방법으로 사용하는게 맞나요 ?
- 미해결[리뉴얼] React로 NodeBird SNS 만들기
로그인 성공 시 페이지
로그인 성공 시 replace를 하는데 이때 로그인 페이지가 따로 있을 경우에 로그인 페이지로 접근하기 직전 페이지로 replace를 하고 싶은데 이전 페이지 url 을 얻는 방법을 아무리 서핑해봐도 모르겠네요. 어떻게 해야 얻을 수 있나요??
- 미해결[리뉴얼] React로 NodeBird SNS 만들기
제로초님 죄송하지만 하나만 더 여쭤볼게요 ㅠ
프론트앤드에서 작업중에 nprogress 없애려고 _app.js에서 관련 코드를 삭제하고 반영이 잘 안되는것 같아서 .next 폴더를 지운후에 빌드했습니다. 그리고는 다시금 git을 통해 pull 했더니 우분투에서 에러가 납니다 해결을 위해 다시금 코드 살려보기도 하고 우분투 서버내에서 node_modules폴더 삭제하고 package-lock.json파일 삭제후에 다시금 npm install 통해 설치해보기도 했는데도 계속 에러나네요 ㅠ 혹시 해결방법을 아시는지요? 부탁드립니다 ㅠ
- 미해결[리뉴얼] React로 NodeBird SNS 만들기
로그인이안되네요.
로그인하면 석세스안되고 대기중입니다.. 사가쪽에 입력한 이메일 받앗나확인하고 이부분하다가 passport local이랑 index다확인하고 비밀번호제거한값으로 user보내고 했는데 왜안되는지모르겟어요... 로그인 리퀘스트의 state를 확인하니 me부분이 null이라 이거때문인거같긴한데 그래서 사가부분에서 데이터 받앗나 확인한거였거든요 원인을 잘모르겟습니다. 노드 워닝 같이올릴게요.. [nodemon] 2.0.14 [nodemon] to restart at any time, enter `rs` [nodemon] watching path(s): *.* [nodemon] watching extensions: js,mjs,json [nodemon] starting `node app.js` 서버 실행중 Executing (default): CREATE TABLE IF NOT EXISTS `Users` (`id` INTEGER NOT NULL auto_increment , `email` VARCHAR(30) NOT NULL UNIQUE, `nickname` VARCHAR(30) NOT NULL, `password` VARCHAR(100) NOT NULL, `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_general_ci; Executing (default): SHOW INDEX FROM `Users` FROM `react-nodebird` Executing (default): CREATE TABLE IF NOT EXISTS `Posts` (`id` INTEGER NOT NULL auto_increment , `content` TEXT NOT NULL, `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL, `UserId` INTEGER, `RetweetId` INTEGER, PRIMARY KEY (`id`), FOREIGN KEY (`UserId`) REFERENCES `Users` (`id`) ON DELETE SET NULL ON UPDATE CASCADE, FOREIGN KEY (`RetweetId`) REFERENCES `Posts` (`id`) ON DELETE SET NULL ON UPDATE CASCADE) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_general_ci; Executing (default): SHOW INDEX FROM `Posts` FROM `react-nodebird` Executing (default): CREATE TABLE IF NOT EXISTS `Images` (`id` INTEGER NOT NULL auto_increment , `src` VARCHAR(200) NOT NULL, `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL, `PostId` INTEGER, PRIMARY KEY (`id`), FOREIGN KEY (`PostId`) REFERENCES `Posts` (`id`) ON DELETE SET NULL ON UPDATE CASCADE) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_general_ci; Executing (default): SHOW INDEX FROM `Images` FROM `react-nodebird` Executing (default): CREATE TABLE IF NOT EXISTS `Hashtags` (`id` INTEGER NOT NULL auto_increment , `name` VARCHAR(20) NOT NULL, `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_general_ci; Executing (default): SHOW INDEX FROM `Hashtags` FROM `react-nodebird` Executing (default): CREATE TABLE IF NOT EXISTS `Comments` (`id` INTEGER NOT NULL auto_increment , `content` TEXT NOT NULL, `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL, `UserId` INTEGER, `PostId` INTEGER, PRIMARY KEY (`id`), FOREIGN KEY (`UserId`) REFERENCES `Users` (`id`) ON DELETE SET NULL ON UPDATE CASCADE, FOREIGN KEY (`PostId`) REFERENCES `Posts` (`id`) ON DELETE SET NULL ON UPDATE CASCADE) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci; Executing (default): SHOW INDEX FROM `Comments` FROM `react-nodebird` Executing (default): CREATE TABLE IF NOT EXISTS `Like` (`createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL, `UserId` INTEGER , `PostId` INTEGER , PRIMARY KEY (`UserId`, `PostId`), FOREIGN KEY (`UserId`) REFERENCES `Users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, FOREIGN KEY (`PostId`) REFERENCES `Posts` (`id`) ON DELETE CASCADE ON UPDATE CASCADE) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_general_ci; Executing (default): SHOW INDEX FROM `Like` FROM `react-nodebird` Executing (default): CREATE TABLE IF NOT EXISTS `Follow` (`createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL, `FollowingId` INTEGER , `FollowerId` INTEGER , PRIMARY KEY (`FollowingId`, `FollowerId`), FOREIGN KEY (`FollowingId`) REFERENCES `Users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, FOREIGN KEY (`FollowerId`) REFERENCES `Users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_general_ci; Executing (default): SHOW INDEX FROM `Follow` FROM `react-nodebird` Executing (default): CREATE TABLE IF NOT EXISTS `PostHashtag` (`createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL, `PostId` INTEGER , `HashtagId` INTEGER , PRIMARY KEY (`PostId`, `HashtagId`), FOREIGN KEY (`PostId`) REFERENCES `Posts` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, FOREIGN KEY (`HashtagId`) REFERENCES `Hashtags` (`id`) ON DELETE CASCADE ON UPDATE CASCADE) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_general_ci; Executing (default): SHOW INDEX FROM `PostHashtag` FROM `react-nodebird` db연결 성공 Executing (default): SELECT `id`, `email`, `nickname`, `password`, `createdAt`, `updatedAt` FROM `Users` AS `User` WHERE `User`.`email` = 'wjdgksak@naver.com';Executing (default): SELECT `User`.`id`, `User`.`email`, `User`.`nickname`, `User`.`createdAt`, `User`.`updatedAt`, `Posts`.`id` AS `Posts.id`, `Followings`.`id` AS `Followings.id`, `Followings->Follow`.`createdAt` AS `Followings.Follow.createdAt`, `Followings->Follow`.`updatedAt` AS `Followings.Follow.updatedAt`, `Followings->Follow`.`FollowingId` AS `Followings.Follow.FollowingId`, `Followings->Follow`.`FollowerId` AS `Followings.Follow.FollowerId`, `Followers`.`id` AS `Followers.id`, `Followers->Follow`.`createdAt` AS `Followers.Follow.createdAt`, `Followers->Follow`.`updatedAt` AS `Followers.Follow.updatedAt`, `Followers->Follow`.`FollowingId` AS `Followers.Follow.FollowingId`, `Followers->Follow`.`FollowerId` AS `Followers.Follow.FollowerId` FROM `Users` AS `User` LEFT OUTER JOIN `Posts` AS `Posts` ON `User`.`id` = `Posts`.`UserId` LEFT OUTER JOIN ( `Follow` AS `Followings->Follow` INNER JOIN `Users` AS `Followings` ON `Followings`.`id` = `Followings->Follow`.`FollowingId`) ON `User`.`id` = `Followings->Follow`.`FollowerId` LEFT OUTER JOIN ( `Follow` AS `Followers->Follow` INNER JOIN `Users` AS `Followers` ON `Followers`.`id` = `Followers->Follow`.`FollowerId`) ON `User`.`id` = `Followers->Follow`.`FollowingId` WHERE `User`.`id` = 1; (node:3728) UnhandledPromiseRejectionWarning: SequelizeDatabaseError: Unknown column 'Posts.UserId' in 'on clause' at Query.formatError (C:\index\nodeNest\back\node_modules\sequelize\lib\dialects\mysql\query.js:265:16) at Query.run (C:\index\nodeNest\back\node_modules\sequelize\lib\dialects\mysql\query.js:77:18) at processTicksAndRejections (internal/process/task_queues.js:97:5) (node:3728) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1) (node:3728) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code. Executing (default): SELECT `id`, `email`, `nickname`, `password`, `createdAt`, `updatedAt` FROM `Users` AS `User` WHERE `User`.`email` = 'wjdgksak@naver.com';Executing (default): SELECT `User`.`id`, `User`.`email`, `User`.`nickname`, `User`.`createdAt`, `User`.`updatedAt`, `Posts`.`id` AS `Posts.id`, `Followings`.`id` AS `Followings.id`, `Followings->Follow`.`createdAt` AS `Followings.Follow.createdAt`, `Followings->Follow`.`updatedAt` AS `Followings.Follow.updatedAt`, `Followings->Follow`.`FollowingId` AS `Followings.Follow.FollowingId`, `Followings->Follow`.`FollowerId` AS `Followings.Follow.FollowerId`, `Followers`.`id` AS `Followers.id`, `Followers->Follow`.`createdAt` AS `Followers.Follow.createdAt`, `Followers->Follow`.`updatedAt` AS `Followers.Follow.updatedAt`, `Followers->Follow`.`FollowingId` AS `Followers.Follow.FollowingId`, `Followers->Follow`.`FollowerId` AS `Followers.Follow.FollowerId` FROM `Users` AS `User` LEFT OUTER JOIN `Posts` AS `Posts` ON `User`.`id` = `Posts`.`UserId` LEFT OUTER JOIN ( `Follow` AS `Followings->Follow` INNER JOIN `Users` AS `Followings` ON `Followings`.`id` = `Followings->Follow`.`FollowingId`) ON `User`.`id` = `Followings->Follow`.`FollowerId` LEFT OUTER JOIN ( `Follow` AS `Followers->Follow` INNER JOIN `Users` AS `Followers` ON `Followers`.`id` = `Followers->Follow`.`FollowerId`) ON `User`.`id` = `Followers->Follow`.`FollowingId` WHERE `User`.`id` = 1; (node:3728) UnhandledPromiseRejectionWarning: SequelizeDatabaseError: Unknown column 'Posts.UserId' in 'on clause' at Query.formatError (C:\index\nodeNest\back\node_modules\sequelize\lib\dialects\mysql\query.js:265:16) at Query.run (C:\index\nodeNest\back\node_modules\sequelize\lib\dialects\mysql\query.js:77:18) at processTicksAndRejections (internal/process/task_queues.js:97:5) (node:3728) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 2) Executing (default): SELECT `id`, `email`, `nickname`, `password`, `createdAt`, `updatedAt` FROM `Users` AS `User` WHERE `User`.`email` = 'wjdgksak@naver.com';Executing (default): SELECT `User`.`id`, `User`.`email`, `User`.`nickname`, `User`.`createdAt`, `User`.`updatedAt`, `Posts`.`id` AS `Posts.id`, `Followings`.`id` AS `Followings.id`, `Followings->Follow`.`createdAt` AS `Followings.Follow.createdAt`, `Followings->Follow`.`updatedAt` AS `Followings.Follow.updatedAt`, `Followings->Follow`.`FollowingId` AS `Followings.Follow.FollowingId`, `Followings->Follow`.`FollowerId` AS `Followings.Follow.FollowerId`, `Followers`.`id` AS `Followers.id`, `Followers->Follow`.`createdAt` AS `Followers.Follow.createdAt`, `Followers->Follow`.`updatedAt` AS `Followers.Follow.updatedAt`, `Followers->Follow`.`FollowingId` AS `Followers.Follow.FollowingId`, `Followers->Follow`.`FollowerId` AS `Followers.Follow.FollowerId` FROM `Users` AS `User` LEFT OUTER JOIN `Posts` AS `Posts` ON `User`.`id` = `Posts`.`UserId` LEFT OUTER JOIN ( `Follow` AS `Followings->Follow` INNER JOIN `Users` AS `Followings` ON `Followings`.`id` = `Followings->Follow`.`FollowingId`) ON `User`.`id` = `Followings->Follow`.`FollowerId` LEFT OUTER JOIN ( `Follow` AS `Followers->Follow` INNER JOIN `Users` AS `Followers` ON `Followers`.`id` = `Followers->Follow`.`FollowerId`) ON `User`.`id` = `Followers->Follow`.`FollowingId` WHERE `User`.`id` = 1; (node:3728) UnhandledPromiseRejectionWarning: SequelizeDatabaseError: Unknown column 'Posts.UserId' in 'on clause' at Query.formatError (C:\index\nodeNest\back\node_modules\sequelize\lib\dialects\mysql\query.js:265:16) at Query.run (C:\index\nodeNest\back\node_modules\sequelize\lib\dialects\mysql\query.js:77:18) at processTicksAndRejections (internal/process/task_queues.js:97:5) (node:3728) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 3) 이건 git주소입니다. https://github.com/MaJunghan/Next.js-and-node 확인하시면 다시 private으로 변경하겠습니다.
- 미해결[리뉴얼] React로 NodeBird SNS 만들기
안녕하세요 제로초님 배포후 에러가 발생해서 문의드립니다 ㅠ
이전과 다른 프로젝트를 만들었는데 또 같은 에러가 ㅠㅠ 처음 에러나는 부분이고 회원가입이나 다른 버튼 클릭시에는 cors, mixed contents 둘다 에러가 나네요 ㅠ app.js const express = require('express'); const cors = require('cors'); const session = require('express-session'); const cookieParser = require('cookie-parser') const passport = require('passport'); const dotenv = require('dotenv'); const morgan = require('morgan'); const path = require('path'); const hpp = require('hpp'); const helmet = require('helmet'); const userRouter = require('./routes/user'); const usersRouter = require('./routes/users'); const jobRouter = require('./routes/job'); const careerRouter = require('./routes/career'); const educationRouter = require('./routes/education'); const activityRouter = require('./routes/activity'); const awardRouter = require('./routes/award'); const certificationRouter = require('./routes/certification'); const certificationsRouter = require('./routes/certifications'); const languageRouter = require('./routes/language'); const projectRouter = require('./routes/project'); const socialRouter = require('./routes/social'); const comtestRouter = require('./routes/comtest'); const comtestsRouter = require('./routes/comtests'); const teamreviewRouter = require('./routes/teamreview'); const teamreviewsRouter = require('./routes/teamreviews'); const teamsearchRouter = require('./routes/teamsearch'); const skillRouter = require('./routes/skill'); const skillsRouter = require('./routes/skills'); const userskillRouter = require('./routes/userskill'); const jobsRouter = require('./routes/jobs'); const db = require('./models'); const passportConfig = require('./passport'); dotenv.config(); const app = express(); // db.sequelize.sync({ force: true }) db.sequelize.sync() .then(() => { console.log('db 연결 성공'); }) .catch(console.error); passportConfig(); //배포를 위한 setting if (process.env.NODE_ENV === "production") { app.use(morgan('combined')) app.use(hpp()); app.use(helmet()); app.use(cors({ origin: 'https://choono.co.kr', credentials: true, // 다른 주소간 cookie 전달 })); } else { // front --> backend 요청시 터미널에 송신상태 표현됨 app.use(morgan('dev')); app.use(cors({ origin: true, credentials: true, // 다른 주소간 cookie 전달 })); } // 업로드한 이미지 보이기 위한 작업 - 경로 맞추기 / static: 정적파일 제공 / join: 현 폴더명+uploads라는 이름을 합쳐 // '/': localhost:3065"/images"" --> Postform의 경로 참조 app.use('/', express.static(path.join(__dirname, 'uploads'))); // 자리위치 고정, front(saga)에서 받은 data를 req.body로 넘겨줌 / axios형태 // 즉, front(saga)에서 받은 data를 해석하여 req.body.email 등으로 변경하도록 도움 app.use(express.json()); // 일반 form형태 data 처리 app.use(express.urlencoded({ extended: true })); // 로그인시 front와 back이 같은 data를 갖고있어야 함 // 로그인시 db의 user정보를 다시 브라우저에 보내줄 때 비번: 보안위험요소 존재(암호화해서 cookie형태로 보냄) app.use(cookieParser(process.env.COOKIE_SECRET)); app.use(session({ saveUninitialized: false, resave: false, // proxy: true, // 배포시 secret: process.env.COOKIE_SECRET, // 암호화 cookie: { httpOnly: true, // secure: false, secure: true, // 배포시 domain: process.env.NODE_ENV === 'production' && '.choono.co.kr' } })); // passport 로그인시 활용 app.use(passport.initialize()); app.use(passport.session()); app.get('/', (req, res) => { res.send('hello express'); }) app.use('/user', userRouter); app.use('/users', usersRouter); app.use('/job', jobRouter); app.use('/career', careerRouter); app.use('/activity', activityRouter); app.use('/award', awardRouter); app.use('/certification', certificationRouter); app.use('/certifications', certificationsRouter); app.use('/language', languageRouter); app.use('/project', projectRouter); app.use('/social', socialRouter); app.use('/education', educationRouter); app.use('/comtest', comtestRouter); app.use('/comtests', comtestsRouter); app.use('/teamreview', teamreviewRouter); app.use('/teamreviews', teamreviewsRouter); app.use('/teamsearch', teamsearchRouter); app.use('/skill', skillRouter); app.use('/skills', skillsRouter); app.use('/userskill', userskillRouter); app.use('/jobs', jobsRouter); app.listen(3065, () => { console.log("서버 실행중!") }); config/config.js (프론트) export const backUrl = 'https://api.choono.co.kr'; // export const backUrl = "http://3.34.2.218"; // Ubuntu 빌드시 검토 // exports.backUrl = 'http://localhost:3065'; 코드작성에는 이상없다고 생각했는데 문제를 찾아봐도 해결방법이 나오질 않네요 ㅠㅠ api.도메인.co.kr로 들어가면 잘 작동하는 것 같습니다. 부탁드립니다 ㅠ pm2 모니터시에 처음엔 db연결 완료라고 나오는데 실행중에 아무것도 뜨지 않는 부분에서 문제가 있으려나 모르겠네요 ㅠ 이건 pm2 에러 확인입니다 프론트앤드 package.json { "name": "choono-front", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "dev": "next -p 3060", "build": "cross-env NODE_OPTIONS=--max-old-space-size=8192 NODE_ENV=production ANALYZE=true next build", "start": "cross-env NODE_OPTIONS=--max-old-space-size=8192 NODE_ENV=production next start -p 3060" }, "author": "SehwanJun", "license": "ISC", "dependencies": { "@ant-design/icons": "^4.6.4", "@next/bundle-analyzer": "^11.1.2", "antd": "^4.3.0", "axios": "^0.21.4", "babel-plugin-styled-components": "^1.13.2", "cross-env": "^7.0.3", "immer": "^9.0.6", "moment": "^2.29.1", "nanoid": "^3.1.25", "next": "^9.5.5", "next-redux-wrapper": "^6.0.2", "nprogress": "^0.2.0", "pm2": "^5.1.2", "prop-types": "^15.7.2", "react": "^17.0.2", "react-dom": "^17.0.2", "react-quill": "^1.3.5", "react-redux": "^7.2.5", "react-tooltip": "^4.2.21", "redux": "^4.1.1", "redux-devtools-extension": "^2.13.9", "redux-saga": "^1.1.3", "styled-components": "^5.3.1" }, "devDependencies": { "babel-eslint": "^10.1.0", "eslint": "^7.32.0", "eslint-config-airbnb": "^18.2.1", "eslint-plugin-import": "^2.24.2", "eslint-plugin-jsx-a11y": "^6.4.1", "eslint-plugin-react": "^7.25.2", "eslint-plugin-react-hooks": "^4.2.0" } } 백앤드 package.json { "name": "choono-back", "version": "1.0.0", "description": "", "main": "app.js", "scripts": { "dev": "nodemon app", "start": "cross-env NODE_ENV=production pm2 start app.js" }, "author": "SehwanJun", "license": "ISC", "dependencies": { "aws-sdk": "^2.1022.0", "axios": "^0.24.0", "bcrypt": "^5.0.1", "cookie-parser": "^1.4.5", "cors": "^2.8.5", "cross-env": "^7.0.3", "dotenv": "^10.0.0", "express": "^4.17.1", "express-session": "^1.17.2", "helmet": "^4.6.0", "hpp": "^0.2.3", "morgan": "^1.10.0", "multer": "^1.4.3", "multer-s3": "^2.10.0", "mysql2": "^2.3.0", "passport": "^0.4.1", "passport-kakao": "^1.0.1", "passport-local": "^1.0.0", "passport-naver": "^1.0.6", "pm2": "^5.1.2", "sequelize": "^6.6.5", "sequelize-cli": "^6.2.0" }, "devDependencies": { "nodemon": "^2.0.12" } }
- 미해결[리뉴얼] React로 NodeBird SNS 만들기
input 파일 업로드시 다른정보는 넘어가는데 file정보가 넘어가지 않는 현상
안녕하세요 개인작업중에 질문이있습니다. 서버와 통신중 백엔드 서버에 게시글 올리는 기능을 만드는데 다른 정보들은 넘어가는데 이미지 파일만 넘어가지 않는 현상이 있어서 질문드립니다. 통신 방법과 이미지 데이터 바꾸기 등을 하여도 넘어가지 않습니다. 코드입니다 import React, { useCallback, useEffect, useRef, useState } from 'react'; import Router from 'next/router'; import MainLayout from '../components/MainLayout'; import style from '../styles/css/upload.module.css'; import useInput from '../hooks/useInput'; import { useDispatch, useSelector } from 'react-redux'; import { ADD_POST_REQUEST, LOAD_POSTS_REQUEST, UPLOAD_IMAGES_REQUEST, } from '../reducers/post'; import { POST_CARD } from '../reducers/menu'; import axios from 'axios'; const Home = () => { const dispatch = useDispatch(); const { me } = useSelector((state) => state.user); const { mainPosts, addPostDone, imagePaths } = useSelector( (state) => state.post, ); const [photoToAddList, setPhotoToAddList] = useState([]); const [content, onChangeContent, setContetn] = useInput(); const [notice, onChangeNotice, setNotice] = useInput(false); const ref = useRef(); const handleResizeHeight = useCallback(() => { if (ref === null || ref.current === null) { return; } ref.current.style.height = '20px'; ref.current.style.height = ref.current.scrollHeight + 'px'; }, []); //댓글창 크기 자동조절 useEffect(() => { if (!me) { Router.push('/'); } }, [me]); const checkboxClick = useCallback(() => { setNotice((prev) => !prev); }, [notice]); const imageInput = useRef(); const onClickImageUpload = useCallback(() => { imageInput.current.click(); }, [imageInput.current]); // 이미지 파일 변수에 저장 const handleImage = useCallback( (e) => { const temp = []; const photoToAdd = e.target.files; for (let i = 0; i < photoToAdd.length; i++) { console.log(photoToAdd); temp.push({ id: photoToAdd[i].name, file: photoToAdd[i], url: URL.createObjectURL(photoToAdd[i]), }); } if (temp.length > 10) { return alert('최대개수 10개가 넘어갔습니다'); } if (temp.length + photoToAddList.length > 10) { return alert('최대개수 10개가 넘어갔습니다'); } if (photoToAddList.length > 10) { return alert('최대개수 10개가 넘어갔습니다'); } setPhotoToAddList(temp.concat(photoToAddList)); // setPhoto(temp.push(temp.forEach((v) => v))); }, [photoToAddList], ); const onRemove = useCallback( (deleteUrl) => { setPhotoToAddList(photoToAddList.filter((v) => v.url !== deleteUrl)); }, [photoToAddList], ); const upLoadFormClick = useCallback( (e) => { e.preventDefault(); if (!photoToAddList.length > 0) { alert('이미지를 등록해주세요'); return; } if (!content) { alert('내용을 등록해주세요'); return; } dispatch({ type: ADD_POST_REQUEST, data: { bo_writer: me.id, bo_content: content, bo_image: photoToAddList, }, }); dispatch({ type: LOAD_POSTS_REQUEST, data: { mem_id: me?.id, }, }); setTimeout(() => { if (addPostDone) { Router.push('/'); dispatch({ type: POST_CARD, }); } }, 1000); }, [photoToAddList, content, addPostDone], ); return ( <> <MainLayout> <div style={{ paddingTop: '24px' }}></div> <section className={style.a}> <article className={style.maxWidth}> <form encType="multipart/form-data" onSubmit={upLoadFormClick} className={style.upLoadForm} > {me?.grade === 'admin' && ( <div> <span>공지</span> <input name="mem_flag" type="checkbox" value={notice} onClick={checkboxClick} // required /> </div> )} <div className={style.imageBox}> {/* /분리 */} <ul> {photoToAddList ? photoToAddList.map((v) => { return ( <li key={v.url}> <div className={style.remove} onClick={() => onRemove(v.url)} > x </div> <img src={v.url} style={{ backgroundImage: `url(${v.url})`, }} /> </li> ); }) : null} <li onClick={onClickImageUpload}> <div className={style.imageInput}> <img src="/icon/addphoto.svg" className={style.addImg} /> </div> </li> </ul> </div> <input name="bo_image" type="file" accept="image/jpg, image/jpeg, image/png" ref={imageInput} onChange={handleImage} hidden multiple required /> <div className={style.textInput}> <textarea name="bo_content" type="text" placeholder="문구를 입력해주세요" ref={ref} onInput={handleResizeHeight} onChange={onChangeContent} maxLength={140} required /> <button>게시</button> </div> </form> </article> </section> <div style={{ paddingBottom: '44px' }}></div> </MainLayout> </> ); }; Home.propTypes = {}; export default Home; // 게시물 등록하기 function addPostAPI(data) { console.log(data, 'data'); return axios.post( `/board/insert.do?bo_writer=${data.bo_writer}&bo_content=${data.bo_content}&bo_image=${data.bo_image}`, data, ); } function* addPost(action) { try { const result = yield call(addPostAPI, action.data); console.log(result); yield put({ type: ADD_POST_SUCCESS, data: result.data, }); } catch (error) { console.error(error); yield put({ type: ADD_POST_FAILURE, data: error.response.data, }); } }
- 해결됨[리뉴얼] React로 NodeBird SNS 만들기
질문드립니다 getServerSideProps or getInitialProps
만약 모든 페이지에서 사용자 정보가 SSR되어야한다면 getServerSideProps보다 getInitalProps로 _app에다가 설정하는게 나을꺼 같은데 혹시 이 방법 말고 더 좋은 방법이 있을까 여쭤봅니다. getInitalProps는 레거시 코드니까 사용하지 않는 게 좋다는데 이거 말고 대안을 못 찾겠네요.ㅠㅠ 1. _app -> getInitalProps MyApp.getInitialProps = wrapper.getInitialAppProps( (store) => async ({ Component, ctx }) => { store.dispatch( setCredentials({ user: await axios .get("http://localhost:4000/users/me", { withCredentials: true, headers: { cookie: ctx.req?.headers.cookie || "", }, }) .then((response) => response.data) .catch(() => null), }) ); return { pageProps: { ...(Component.getInitialProps ? await Component.getInitialProps({ ...ctx, store }) : {}), pathname: ctx.pathname, }, }; } ); 2. pages -> getServerSideProps wrapper.getServerSideProps((store) => async (context) => { store.dispatch( setCredentials({ user: await axios .get("http://localhost:4000/users/me", { withCredentials: true, headers: { cookie: context.req.headers.cookie || "", }, }) .then((response) => response.data) .catch(() => null), }) ); return {props: {}}; });
- 미해결[리뉴얼] React로 NodeBird SNS 만들기
제가 백엔드 sql port 번호설정을 잘못한거 같습니다..
영상을 보면 브라우저 3060 프론트 서버(Next) (3060) 백엔드 서버(express) (3065) MySQL(3306)라고 되어있는데 저는 제꺼는 프론트 서버는 3060이고 백엔드 서버는3000이고 MySQL 3306으로 들어가면 아래오류가 뜨고 3000번으로 들어가면 로그인이 됩니다. 어디서부터 잘못된 느낌이 들어서 질문올립니다.... 프론트 서버이고 백엔드 서버입니다. 그리고 백엔드 서버에서 port를 3000으로 맞춰줘야 db연결 성공이 떠서 3000으로 맞췄습니다..
- 미해결[리뉴얼] React로 NodeBird SNS 만들기
cors 질문입니다.
cors 는 브라우저에서 다른 서버로 도메인이 다른곳으로 url에 요청을 보낼떄 나타나고 , 프론트서버에서 백엔드서버로 요청보낼땐 상관없다고하셧는데, 저희의 방식은 요청을 saga에서받아서 (프론트서버), 요청을 하는것이아닌가요 ? 그럼 서버에서 서버라 cors 문제가 없어야 정상아닌지요 ? 궁금해서 여쭤봅니다.
- 미해결[리뉴얼] React로 NodeBird SNS 만들기
안녕하세요 제로초님 에러 질문입니다.
영상 2분 59초 쯤에 node app을 하는 순간 unexpected token 'export'라고 나왔습니다. 구글링을 하고 영상을 다시 돌려봤는데 어떤 문제점인지 몰라서 이렇게 질문 드립니다. 아래는 routes폴더의 post.js파일입니다.
- 미해결[리뉴얼] React로 NodeBird SNS 만들기
React 인라인 스타일 DOM 업데이트 관련해서 질문드립니다.
안녕하세요? 리렌더링 강의 중에 React의 인라인 스타일 객체가 리렌더링 시 새로 그려진다는 부분에 궁금한 점이 생겨 질문드립니다. 먼저 해당 컴포넌트가 리렌더링 될 때 Element가 인라인 스타일로 할당이 되면 그 자식 요소들도 다시 그려진다고 이해를 했는데요 아래 사진과 같이 테스트를 해봤는데 a가 버튼 클릭 시 바뀔 때마다 리렌더링이 될 때 Form에 인라인스타일을 적용했음에도 a를 사용하는 div이외에는 다시 그려지지 않는 것을 개발자도구로 확인을 했습니다. 혹시 제가 잘 못 이해한 부분이 있나요? 감사합니다.
- 미해결[리뉴얼] React로 NodeBird SNS 만들기
카카오 로그인 적용 관련해서 질문 드릴게요
안녕하세요 제로초님 강좌 너무 잘 들었습니다. 강의를 다 듣고난 뒤 저만의 크롬 확장 프로그램을 만들고 호스팅만 남겨놓은 상태입니다. 저는 passport 전략으로 카카오와 구글 로그인을 사용하였고 세션을 mysql에 저장하여 자동 로그인 기능을 구현했습니다. 문제는 역시 aws로 배포할 때 브라우저로 쿠키가 전달되지 않는 문제입니다. 이미 다른 분들이 질문해 주셔서 답변을 참고했습니다. 답변들을 참고삼아 제가 이해한 원리는 다음과 같습니다. 로그인 시도 => 백엔드에서 로그인 성공 => 카카오 콜백 라우터에서 프론트 api 라우터로 sessionId 전달 => 프론트 라우터에서 전달 받은 sessionId를 쿠키로 저장 => 홈페이지 이동 => 다시 백엔드로 get 요청 => sid 쿠키를 가지고 있기에 deserialize에서 user 정보를 req에 붙여줌 => 정상적으로 req.user 생성 우선 제로초님이 이곳 에서 답변하신 내용을 참고삼아서 카카오 콜백에서 프론트 라우터로 sessionId를 url로 보내주었습니다. ---------- router.get( "/kakao/callback", passport.authenticate("kakao", { failureRedirect: "/login", }), async (req, res) => { const sessionId = req.sessionID; const passportId = req.session.passport.user; res.redirect( `http://3.38.99.75/api/login?sid=${sessionId}&pid=${passportId}` ); } } ); -------- // front/api/login export default function handler(req, res) { const sid = req.query.sid; const pid = req.query.pid; res.setHeader("Set-Cookie", [ "connect.sid=" + sid + ";" + "path=/;", "passportId=" + pid + ";" + "path=/;", ]); res.redirect("/"); } --------- 이렇게 한 뒤 프론트에서 백엔드로 요청을 할 때 쿠키가 전달되었지만, 로그인이 되지 않습니다. 문제가 무엇인지 생각해보니 개발환경에서 보았던 값과 조금 다른것 같습니다. 개발환경에서는 SessionID값 뒤에 점이 붙은 뒤 추가 문자열이 생성되서 쿠키가 저장됩니다. 하지만 배포환경에서 제가 SessionId 값을 얻을 때는 정말 딱 session id 값만 받습니다. 로그인 후 프론트 라우터에서 홈페이지로 이동하고 그곳에서 백엔드로 보내는 첫 get 요청을 라우터로 확인하면 아래와 같습니다. 세션쿠키를 첨부해서 요청을 보내도 deserialize에서 req.user를 생성해주지 않습니다. 도저히 원인을 모르겠습니다. 이분이 해결한 방법처럼 콜백에서 passport를 호출 해보았지만 원리를 잘 모르겠고 이게 맞는 방법인지도 모르겠습니다. ------------- router.get( "/kakao/callback", passport.authenticate("kakao", { failureRedirect: "/login", }), async (req, res) => { req.login(req.user, () => { req.login( req.user, () => { } ) }) } ); ------------- 이 문제 때문에 프로젝트 다 만들어 놓고 3일 째 끙끙 대며 호스팅을 못하고 있습니다. ㅜㅜ 왜 sessionId가 쿠키로 전달되는데도 로그인이 되지 않을까요?? 혹시 다른 호스팅 서비스나 aws 서버리스를 사용해도 똑같은 문제가 발생할까요?? 바쁘실텐데 봐주셔서 감사드립니다. 참고로 github 주소는 https://github.com/ChangKeunJi/pickle 입니다.
- 미해결[리뉴얼] React로 NodeBird SNS 만들기
배포 시 mysql을 쓸지 RDS를 쓸지 고려 기준
안녕하세요, 제로초님 서비스를 배포하는 실습을 진행중인데, 한가지 질문드릴게 있어서 질문드립니다. AWS에 RDS 시스템을 사용하지 않고 back-server에 mysql 설치 하였을때, 한계점이라고 할 부분이 용량적인 부분일까요?? DB 용량이 많을것으로 예상 될 때 RDS 서비스를 이용해야하는지 궁금해서 질문드려요.
- 미해결[리뉴얼] React로 NodeBird SNS 만들기
제로초님 각 id 값 마다 특정 이미지 넣기
제로초님 안녕하세요 다름이 아니라. 제가 신발 상세 페이지에서 json 에 신발 사이즈 Array(10) 개가 있고. 0,1,2,3,4,5,6,7,8,9,10 이 있습니다 id 값이. 각 id 값 마다 이미지를 부여 하고 싶습니다. 예시로 들자면? 만약 Array 중 id 값 -> 8 인 값에 예시로 구름 이미지를 넣어주고 싶고, id 값 중 5 인 값에는 햇님 이미지를 넣어주고 싶습니다. 제가 프론트쪽 공부해서. 백단에서 이미지를 넣어주면 되지만, 프론트에서 한번 id 값마다 특정 이미지를 넣어주고 싶은데 어떻게 해야 할 지 감이 안옵니다 ㅠㅠㅠ 도와주세요
- 미해결[리뉴얼] React로 NodeBird SNS 만들기
mariaDB 사용중이라 포트 3307 햇는데
생성됫다고 떳는데 포트번호도 같고 근데 실제로 들어가보면 테이블이없는뎁숑?