• 카테고리

    질문 & 답변
  • 세부 분야

    모바일 앱 개발

  • 해결 여부

    해결됨

백 서버 터미널 오류

23.03.14 19:39 작성 조회수 336

0

        const token = await EncryptedStorage.getItem('refreshToken');
        if (!token) {
          SplashScreen.hide(); // here
          return;
        }
        ...
      } finally {
        SplashScreen.hide();  // here
      }
    };
    getTokenAndRefresh();
  }, [dispatch]);

강의 따라서 SplashScreen.hide() 잘 해주었는데,

이 상태에서 멈추고 갑자기 back 서버 터미널이 무한 로딩되는데... back 서버를 껐다가 다시 켰는데 로그인이 되어있으면 안되는데 되어있는 상황입니다

import * as React from 'react';
import {useEffect} from 'react';
import {useSelector} from 'react-redux';
import {NavigationContainer} from '@react-navigation/native';
import {createNativeStackNavigator} from '@react-navigation/native-stack';
import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';
import Settings from './src/pages/Settings';
import Orders from './src/pages/Orders';
import Delivery from './src/pages/Delivery';
import SignIn from './src/pages/SignIn';
import SignUp from './src/pages/SignUp';
import {RootState} from './src/store/reducer';
import useSocket from './src/hooks/useSocket';
import EncryptedStorage from 'react-native-encrypted-storage';
import axios, {Axios, AxiosError} from 'axios';
import Config from 'react-native-config';
import userSlice from './src/slices/user';
import {useAppDispatch} from './src/store';
import {Alert} from 'react-native';
import orderSlice from './src/slices/order';
import usePermissions from './src/hooks/usePermissions';
import SplashScreen from 'react-native-splash-screen';
import FontAwesome5 from 'react-native-vector-icons/FontAwesome5';
import FontAwesome from 'react-native-vector-icons/FontAwesome';

export type LoggedInParamList = {
  Orders: undefined;
  Settings: undefined;
  Delivery: undefined;
  Complete: {orderId: string};
};

export type RootStackParamList = {
  SignIn: undefined;
  SignUp: undefined;
};

const Tab = createBottomTabNavigator();
const Stack = createNativeStackNavigator<RootStackParamList>();

function AppInner() {
  const dispatch = useAppDispatch();
  const isLoggedIn = useSelector((state: RootState) => !!state.user.email);
  const [socket, disconnect] = useSocket();

  usePermissions();

  useEffect(() => {
    axios.interceptors.response.use(
      response => {
        // console.log(response);
        return response;
      },
      async error => {
        const {
          config,
          response: {status},
        } = error;
        if (status === 419) {
          if (error.response.data.code === 'expired') {
            const originalRequest = config;
            const refreshToken = await EncryptedStorage.getItem('refreshToken');
            // token refresh 요청
            const {data} = await axios.post(
              `${Config.API_URL}/refreshToken`, // token refresh api
              {},
              {headers: {authorization: `Bearer ${refreshToken}`}},
            );
            // 새로운 토큰 저장
            dispatch(userSlice.actions.setAccessToken(data.data.accessToken));
            originalRequest.headers.authorization = `Bearer ${data.data.accessToken}`;
            // 419로 요청 실패했던 요청 새로운 토큰으로 재요청
            return axios(originalRequest);
          }
        }
        return Promise.reject(error);
      },
    );
  }, [dispatch]);

  useEffect(() => {
    const callback = (data: any) => {
      console.log(data);
      dispatch(orderSlice.actions.addOrder(data));
    };
    if (socket && isLoggedIn) {
      socket.emit('acceptOrder', 'hello');
      socket.on('order', callback);
    }
    return () => {
      if (socket) {
        socket.off('order', callback);
      }
    };
  }, [dispatch, isLoggedIn, socket]);

  useEffect(() => {
    if (!isLoggedIn) {
      console.log('!isLoggedIn', !isLoggedIn);
      disconnect();
    }
  }, [isLoggedIn, disconnect]);

  // 앱 실행 시, 토큰 있으면 로그인하는 코드
  useEffect(() => {
    const getTokenAndRefresh = async () => {
      try {
        const token = await EncryptedStorage.getItem('refreshToken');
        if (!token) {
          SplashScreen.hide();
          return;
        }
        const response = await axios.post(
          `${Config.API_URL}/refreshToken`,
          {},
          {
            headers: {
              authorization: `Bearer ${token}`,
            },
          },
        );
        dispatch(
          userSlice.actions.setUser({
            name: response.data.data.name,
            email: response.data.data.email,
            accessToken: response.data.data.accessToken,
          }),
        );
      } catch (error) {
        console.error(error);
        if (((error as AxiosError).response?.data as any).code === 'expired') {
          Alert.alert('알림', '다시 로그인 해주세요.');
        }
      } finally {
        // TODO: 스플래시 스크린 없애기
        SplashScreen.hide();
      }
    };
    getTokenAndRefresh();
  }, [dispatch]);

  return (
    <NavigationContainer>
      {isLoggedIn ? (
        <Tab.Navigator>
          <Tab.Screen
            name="Orders"
            component={Orders}
            options={{
              title: '오더 목록',
              tabBarIcon: () => <FontAwesome5 name="list" size={20} />,
            }}
          />
          <Tab.Screen
            name="Delivery"
            component={Delivery}
            options={{
              headerShown: false,
              title: '지도',
              tabBarIcon: () => <FontAwesome5 name="map" size={20} />,
              // headerTitleStyle: {fontWeight: 'bold'},
              // tabBarLabelStyle: {fontSize: 12},
            }}
          />
          <Tab.Screen
            name="Settings"
            component={Settings}
            options={{
              title: '내 정보',
              tabBarIcon: () => <FontAwesome name="gear" size={20} />,
              unmountOnBlur: true,
            }}
          />
        </Tab.Navigator>
      ) : (
        <Stack.Navigator>
          <Stack.Screen
            name="SignIn"
            component={SignIn}
            options={{title: '로그인'}}
          />
          <Stack.Screen
            name="SignUp"
            component={SignUp}
            options={{title: '회원가입'}}
          />
        </Stack.Navigator>
      )}
    </NavigationContainer>
  );
}

export default AppInner;

 

아래는 백 서버 터미널 입니다 (이 부분이 계속 로딩됩니다)

C:\Users\user\fooddeliveryapp\back>npm start

> food-delivery-server@1.0.0 start
> node app.js

연결되었습니다.
TokenExpiredError: jwt expired
    at C:\Users\user\fooddeliveryapp\back\node_modules\jsonwebtoken\verify.js:152:21
    at getSecret (C:\Users\user\fooddeliveryapp\back\node_modules\jsonwebtoken\verify.js:90:14)       
    at module.exports [as verify] (C:\Users\user\fooddeliveryapp\back\node_modules\jsonwebtoken\verify.js:94:10)
    at verifyRefreshToken (C:\Users\user\fooddeliveryapp\back\app.js:59:22)
    at Layer.handle [as handle_request] (C:\Users\user\fooddeliveryapp\back\node_modules\express\lib\router\layer.js:95:5)
    at next (C:\Users\user\fooddeliveryapp\back\node_modules\express\lib\router\route.js:137:13)      
    at Route.dispatch (C:\Users\user\fooddeliveryapp\back\node_modules\express\lib\router\route.js:112:3)
    at Layer.handle [as handle_request] (C:\Users\user\fooddeliveryapp\back\node_modules\express\lib\router\layer.js:95:5)
    at C:\Users\user\fooddeliveryapp\back\node_modules\express\lib\router\index.js:281:22
    at Function.process_params (C:\Users\user\fooddeliveryapp\back\node_modules\express\lib\router\index.js:341:12) {
  expiredAt: 2023-03-14T08:00:16.000Z
}
POST /refreshToken 419 91.985 ms - 70

잘 되다가 갑자기 이러니 당황스럽네요...ㅎㅎ

메트로 서버에서는 이렇게 나오네요

 LOG  Running "FoodDeliveryApp" with {"rootTag":11}
 LOG  !isLoggedIn true
 LOG  check location granted

백 서버를 껐다가 켠건데 왜 로그인이 되어있는 상태로 나올까요?

답변 1

답변을 작성해보세요.

1

refreshToken 자체가 만료돼서 그렇네요. await EncryptedStorage.clear() 한 번 제일 위에서 호출해서 jwt 지운 후에 다시 코드도 제거하세요.