-
카테고리
-
세부 분야
백엔드
-
해결 여부
해결됨
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
조현영
지식공유자2023.06.28
async signin(@User() user: Users) {
console.log('user', user);
return user;
}
하고 user 정보가 백엔드 콘솔에 뜨는지 봐보세요.
성은김
질문자2023.06.28
어지간한 부분들은 전부 콘솔로 걸어 확인 후에 정말 이해가 안되어서 여쭤봅니다!....
해당 콘솔 데이터입니다.
user: { id: 9, email: 'sinde530@naver.com'}
성은김
질문자2023.06.28
답변 감사합니다!.
정확하게 어떤 답변을 드려야하는지 애매하여서 사진들 첨부드립니다.
이해 부탁드립니다!
users관련
로그인 하였을때.
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;
조현영
지식공유자2023.06.28
로그인 시 비밀번호를 틀린 경우에도 저기 response에 비밀번호가 틀렸습니다라는 메시지가 없나요?
지금 코드는 정상적인것같은데 응답이 안 가네요
조현영
지식공유자2023.06.28
httpException은 에러 시에만 동작하고 데이터를 잘 내려주고 있으니 문제없습니다.
성공 시에 데이터가 안 가는 게 문제인데 interceptor쪽 봐야할 것 같습니다.
성은김
질문자2023.06.28
앗 감사합니다. 공식문서보고 조금 변형을 시켜서 진행을 하였더니 데이터가 출력이 되지 않았던거였습니다. 저의 코드에선 항상 undefined값을 가지게 되어 그런 현상이 발생된거였습니다.
트러블슈팅 메모메모..
답변 1