inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

묻고 답해요

173만명의 커뮤니티!! 함께 토론해봐요.

fe `내 정보 조회`시 프론트에서 데이터 불러오지 못합니다.

해결됨

Slack 클론 코딩[백엔드 with NestJS + TypeORM]

조현영님 안녕하세요. 프론트, 백엔드 강좌를 잘 보고있습니다! 현영님의 강좌에서 useSwr를 사용하는법을 배우고, 백엔드도 구현해보고자 하여, 백엔드도 수강하게 되었습니다. 회원가입과 로그인을 하였을경우 정상적으로 작동하여, 로그인을 하였을경우, 프론트에게 쿠키값을 제대로 넘겨주고있지만, response 데이터를 받지 못하고있는데 원인을 알 수가 없습니다. front에서 로그인 하였을시 나오는 콘솔 data user: {data: '', status: 200, statusText: 'OK', headers: AxiosHeaders, config: {…}, …} installHook.js:342 data user: {data: '', status: 200, statusText: 'OK', headers: AxiosHeaders, config: {…}, …} fetcher.ts:6 response: {data: '', status: 200, statusText: 'OK', headers: AxiosHeaders, config: {…}, …} index.tsx:91 back에서 로그인 request받았을때, 응답하는 콘솔 [Nest] 69849 - 06/28/2023, 10:09:06 AM LOG [HTTP] GET /api/users 200 undefined - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 ::1 query: SELECT DISTINCT `distinctAlias`.`Users_id` AS `ids_Users_id` FROM (SELECT `Users`.`id` AS `Users_id`, `Users`.`email` AS `Users_email`, `Users`.`nickname` AS `Users_nickname`, `Users__Users_Workspaces`.`id` AS `Users__Users_Workspaces_id`, `Users__Users_Workspaces`.`name` AS `Users__Users_Workspaces_name`, `Users__Users_Workspaces`.`url` AS `Users__Users_Workspaces_url`, `Users__Users_Workspaces`.`createdAt` AS `Users__Users_Workspaces_createdAt`, `Users__Users_Workspaces`.`updatedAt` AS `Users__Users_Workspaces_updatedAt`, `Users__Users_Workspaces`.`deletedAt` AS `Users__Users_Workspaces_deletedAt`, `Users__Users_Workspaces`.`OwnerId` AS `Users__Users_Workspaces_OwnerId` FROM `users` `Users` LEFT JOIN `workspacemembers` `Users_Users__Users_Workspaces` ON `Users_Users__Users_Workspaces`.`UserId`=`Users`.`id` LEFT JOIN `workspaces` `Users__Users_Workspaces` ON `Users__Users_Workspaces`.`id`=`Users_Users__Users_Workspaces`.`WorkspaceId` AND (`Users__Users_Workspaces`.`deletedAt` IS NULL) WHERE ( (`Users`.`id` = ?) ) AND ( `Users`.`deletedAt` IS NULL )) `distinctAlias` ORDER BY `Users_id` ASC LIMIT 1 -- PARAMETERS: [9] query: SELECT `Users`.`id` AS `Users_id`, `Users`.`email` AS `Users_email`, `Users`.`nickname` AS `Users_nickname`, `Users__Users_Workspaces`.`id` AS `Users__Users_Workspaces_id`, `Users__Users_Workspaces`.`name` AS `Users__Users_Workspaces_name`, `Users__Users_Workspaces`.`url` AS `Users__Users_Workspaces_url`, `Users__Users_Workspaces`.`createdAt` AS `Users__Users_Workspaces_createdAt`, `Users__Users_Workspaces`.`updatedAt` AS `Users__Users_Workspaces_updatedAt`, `Users__Users_Workspaces`.`deletedAt` AS `Users__Users_Workspaces_deletedAt`, `Users__Users_Workspaces`.`OwnerId` AS `Users__Users_Workspaces_OwnerId` FROM `users` `Users` LEFT JOIN `workspacemembers` `Users_Users__Users_Workspaces` ON `Users_Users__Users_Workspaces`.`UserId`=`Users`.`id` LEFT JOIN `workspaces` `Users__Users_Workspaces` ON `Users__Users_Workspaces`.`id`=`Users_Users__Users_Workspaces`.`WorkspaceId` AND (`Users__Users_Workspaces`.`deletedAt` IS NULL) WHERE ( (`Users`.`id` = ?) ) AND ( `Users`.`deletedAt` IS NULL ) AND ( `Users`.`id` IN (9) ) -- PARAMETERS: [9] getUsers user: Users { id: 9, email: 'sinde530@naver.com', nickname: '이카자', Workspaces: [] } [Nest] 69849 - 06/28/2023, 10:09:18 AM LOG [HTTP] GET /api/users 200 undefined - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 ::1 코드들 // user.controller.ts import { Body, Controller, Get, Post, Req, Res, UseGuards, UseInterceptors, } from '@nestjs/common'; import { ApiCookieAuth, ApiOperation, ApiResponse, ApiTags, } from '@nestjs/swagger'; import { LocalAuthGuard } from 'src/auth/local-auth.guard'; import { LoggedInGuard } from 'src/auth/logged-in.guard'; import { NotLoggedInGuard } from 'src/auth/not-logged-in.guard'; import { User } from 'src/common/decoraters/users.decorater'; import { UserDto } from 'src/common/dto/user.dto'; import { UndefinedToNullInterceptor } from 'src/common/interceptors/undefinedToNull.interceptor'; import { Users } from 'src/entities/Users'; import { SignUpRequestDto } from './dto/signup.request.dto'; import { UsersService } from './users.service'; @UseInterceptors(UndefinedToNullInterceptor) @ApiTags('Users') @Controller('api/users') export class UsersController { constructor(private usersService: UsersService) {} @ApiResponse({ status: 200, description: '성공', type: UserDto, }) @ApiResponse({ status: 500, description: '서버 에러', }) @ApiCookieAuth('connect.sid') @ApiOperation({ summary: '내 정보 조회' }) @Get() async getUsers(@User() user: Users) { console.log('getUsers user:', user); return user || false; } @ApiOperation({ summary: '회원가입' }) @UseGuards(NotLoggedInGuard) @Post('signup') async signup(@Body() data: SignUpRequestDto) { await this.usersService.postUsers(data.email, data.nickname, data.password); } @ApiResponse({ status: 200, description: '로그인 성공', type: UserDto, }) @ApiResponse({ status: 500, description: '서버 에러', }) @ApiOperation({ summary: '로그인' }) @UseGuards(LocalAuthGuard) @Post('signin') async signin(@User() user: Users) { return user; } @ApiOperation({ summary: '로그아웃' }) @UseGuards(LoggedInGuard) @Post('logout') logOut(@Req() request, @Res() response) { request.logOut(); response.clearCookie('connect.sid', { httpOnly: true }); response.send('ok'); } } // SignIn.tsx import axios from 'axios'; import { useCallback, useState } from 'react'; import useInput from 'src/hooks/useInput'; import fetcher from 'src/utils/fetcher'; import useSWR from 'swr'; import { Button, Container, Form, InfoBox, Input, LoginInfoBox, LoginLink, LoginText, Logo, RegisterBox, RegisterErrorText, RegisterText, SubContainer, WelcomeBox, WelcomeText, WrapperImageLogo, } from './styled'; export default function SignIn() { const { data, error, mutate } = useSWR( 'http://localhost:3090/api/users', fetcher, ); const [email, onChangeEmail] = useInput(''); const [password, onChangePassword] = useInput(''); const emailRegex = /^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/; const [errors, setErrors] = useState({ email: false, password: false, invalidEmail: false, }); const [presentEmail, setPresentEmailError] = useState(false); const [loginError, setLoginError] = useState(false); const Image = 'https://dummyimage.com/600x400/000/fff'; const handleSubmit = useCallback( async (e: any) => { e.preventDefault(); const newErrors = { email: !email, password: !password, invalidEmail: !!(email && !emailRegex.test(email)), }; setPresentEmailError(false); setErrors(newErrors); setLoginError(false); if (Object.values(newErrors).some((error) => error)) { return; } try { await axios .post( 'http://localhost:3090/api/users/signin', { email, password, }, { withCredentials: true }, ) .then(() => { mutate(); }) .catch((error) => { setPresentEmailError(error.response?.data); setLoginError(error); }); } catch (error) { console.error(error); } }, [email, password, mutate], ); console.log('data user:', data); if (error) console.log('error:', error); // if (!error && userData) { // console.log('로그인됨', userData); // return <Navigate to="/workspace/purrfect-chat/channel/general" />; // } return ( <Container> <SubContainer> <WrapperImageLogo> <Logo src={Image} alt="error" /> </WrapperImageLogo> <RegisterBox> <WelcomeBox> <WelcomeText>Welcome to Purrfect Chat!</WelcomeText> </WelcomeBox> <Form> <InfoBox> {errors.email && ( <RegisterErrorText> 이메일을 입력해 주세요. </RegisterErrorText> )} {errors.invalidEmail && ( <RegisterErrorText> 이메일 형식을 입력해 주세요. </RegisterErrorText> )} {loginError && ( <RegisterErrorText> 이메일 또는 비밀번호가 일치하지 않습니다. </RegisterErrorText> )} {!errors.email && !errors.invalidEmail && !presentEmail && ( <RegisterText>이메일</RegisterText> )} <Input name="email" type="text" value={email} onChange={onChangeEmail} /> </InfoBox> <InfoBox> {errors.password && ( <RegisterErrorText> 비밀번호를 입력해 주세요. </RegisterErrorText> )} {loginError && ( <RegisterErrorText> 이메일 또는 비밀번호가 일치하지 않습니다. </RegisterErrorText> )} {!errors.password && !loginError && ( <RegisterText>비밀번호</RegisterText> )} <Input name="password" type="password" autoComplete="true" value={password} onChange={onChangePassword} /> </InfoBox> <InfoBox> <Button type="button" onClick={handleSubmit}> 로그인 </Button> </InfoBox> <LoginInfoBox> <LoginText>아직 회원이 아니신가요?</LoginText> <LoginLink to="/signup"> 회원가입 하러가기 </LoginLink> </LoginInfoBox> </Form> </RegisterBox> </SubContainer> </Container> ); } // fetcher.ts import axios from 'axios'; const fetcher = async (url: string) => { try { const response = await axios.get(url, { withCredentials: true }); console.log('response:', response); return response; } catch (error: any) { throw new Error(error.response?.data); } }; export default fetcher; back/main.ts import { ValidationPipe } from '@nestjs/common'; import { NestFactory } from '@nestjs/core'; import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; import cookieParser from 'cookie-parser'; import session from 'express-session'; import passport from 'passport'; import { AppModule } from './app.module'; import { HttpExceptionFilter } from './httpException.filter'; declare const module: any; async function bootstrap() { const app = await NestFactory.create(AppModule); app.useGlobalFilters(new HttpExceptionFilter()); app.useGlobalPipes( new ValidationPipe({ transform: true, }), ); app.enableCors({ origin: true, credentials: true, }); const config = new DocumentBuilder() .setTitle('HTTP API ') .setDescription('개발 API 문서입니다.') .setVersion('1.0') .addCookieAuth('connect.sid') .build(); const documnet = SwaggerModule.createDocument(app, config); SwaggerModule.setup('api', app, documnet); app.use(cookieParser()); app.use( session({ resave: false, saveUninitialized: false, secret: process.env.COOKIE_SECRET, cookie: { httpOnly: true, }, }), ); app.use(passport.initialize()); app.use(passport.session()); const port = process.env.PORT || 3090; await app.listen(port); console.log(`listening on port ${port}`); if (module.hot) { module.hot.accept(); module.hot.dispose(() => app.close()); } } bootstrap();

  • node.js
  • express
  • typeorm
  • @react
  • react-vite
성은김 댓글 1 좋아요 0 조회수 539

인기 태그

인프런 TOP Writers

주간 인기글