• 카테고리

    질문 & 답변
  • 세부 분야

    백엔드

  • 해결 여부

    해결됨

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

23.06.28 10:58 작성 23.06.28 11:36 수정 조회수 331

0

조현영님 안녕하세요. 프론트, 백엔드 강좌를 잘 보고있습니다! 현영님의 강좌에서 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();

답변 1

답변을 작성해보세요.

1

async signin(@User() user: Users) {
    console.log('user', user);
    return user;
  }

하고 user 정보가 백엔드 콘솔에 뜨는지 봐보세요.

성은김님의 프로필

성은김

질문자

2023.06.28

어지간한 부분들은 전부 콘솔로 걸어 확인 후에 정말 이해가 안되어서 여쭤봅니다!....

해당 콘솔 데이터입니다.

user: { id: 9, email: 'sinde530@naver.com'}

네트워크탭에서 로그인 요청의 response에도 데이터가 비어있나요?

성은김님의 프로필

성은김

질문자

2023.06.28

답변 감사합니다!.
정확하게 어떤 답변을 드려야하는지 애매하여서 사진들 첨부드립니다.
이해 부탁드립니다!

imageimage

 

users관련

imageimage

로그인 하였을때.

fetcher에서 가져오는 콘솔이름은 response입니다.

import axios from 'axios';

const fetcher = async (url: string) => {
    try {
        const response = await axios.get(url, { withCredentials: true });
        console.log('response:', response);
        return response.data;
    } catch (error: any) {
        throw new Error(error.response?.data);
    }
};

export default fetcher;

image

로그인 시 비밀번호를 틀린 경우에도 저기 response에 비밀번호가 틀렸습니다라는 메시지가 없나요?

지금 코드는 정상적인것같은데 응답이 안 가네요

성은김님의 프로필

성은김

질문자

2023.06.28

이메일 or 비밀번호 틀렸을시 이렇게 나옵니다!
해당 문제는 http Exception에서 잘못 내려주고 있어서 그런걸까요?

image

httpException은 에러 시에만 동작하고 데이터를 잘 내려주고 있으니 문제없습니다.

성공 시에 데이터가 안 가는 게 문제인데 interceptor쪽 봐야할 것 같습니다.

성은김님의 프로필

성은김

질문자

2023.06.28

앗 감사합니다. 공식문서보고 조금 변형을 시켜서 진행을 하였더니 데이터가 출력이 되지 않았던거였습니다. 저의 코드에선 항상 undefined값을 가지게 되어 그런 현상이 발생된거였습니다.

 

트러블슈팅 메모메모..