상황 

npm install faker

를 한 후, faker를 사용 후 적용을 했더니 Error : faker.js : NotFound

이유
The developer of these libraries intentionally introduced an infinite loop that bricked thousands of projects that depend on ‘colors’ and ‘faker.’  

-> 라이브러리의 개발자는 의도적으로 '색상' '페이커' 의존하는 수천 개의 프로젝트를 망가뜨리는 무한 루프를 도입했습니다.

해결 

npm install faker@5

구버전으로 버전을 바꿔준 후 해결 할 수 있었습니다.

'개발일지 > Troubleshooting' 카테고리의 다른 글

[Header설정 오류] - 협업 중..  (0) 2023.04.19


  토큰을 발행해준 후, verify 과정에서 Invalid, expired를 처리해줘야 할까 고민이 들었습니다. 그래서 상황에 맞는 시나리오를 그리고 어떻게 해결해 나갈 것인지 코드를 작성하였습니다.

시나리오

1. 로그인을 하면 AccessToken과 RefreshToken을 발행합니다.
 - AccessToken은 Bearer, RefreshToken은 Redis에 저장을 해줍니다.

2. 사용자가 인증일 필요한 API에 접근하고자 할 때, 검증 미들웨어(authMiddleware)를 통해 검사함.
 

  • Case 1 : AccessToken 만료, RefreshToken 만료  : Error
  • Case 2 : AccessToken 만료, RefreshToken 유효 : AccessToken 재발급
  • Case 3 : AccessToken 유효, RefreshToken 만료 : 로그인 재요청
  • Case 4 : AccessToken 유효, RefreshToken 유효 : next

3. 로그아웃

  • AccessToken, RefreshToken 삭제시키기.

🛠Advanced Feacture🛠

const authMiddleware = {

    checkToken: async (req, res, next) => {

        try {
            // accessToken이 만료된 경우에는 새로 발급 받은 accessToken을 받아옵니다. 그 외에는 null로 넘겨줬습니다.
            const { accessToken, result } = await authService.verifyToken(req);
			
            //result를 통해서 ( "(AccessToken||RefreshToken)_(INVALID||EXPIRED)" 를 받아옵니다.
            
            //AccessToken이 변조된 경우
            if (result === ACCESSTOKEN_INVALID) {
                return res.status(403).send({ err: "accessToken is invalid", statusCode: 403, msg: 'Forbidden' });
            }
            //RefreshToken이 변조된 경우
            else if (result === REFRESHTOKEN_INVALID) {
                return res.status(401).send({ err: "refreshToken is invalid", statusCode: 401, msg: '재로그인 해주세요' });
            }
            //AccessToken이 만료된 경우            
            else if (result === ACCESSTOKEN_EXPIRED) {
            	//새로 받아온 accessToken을 Bearer + 새로 발급받은 accessToekn을 넣어줍니다.
                res.header('AccessToken', "Bearer " + accessToken);
                return next();
            }
            //RefreshToken이 만료된 경우
            else if (result === REFRESHTOKEN_EXPIRED) {
                return res.status(401).send({ statusCode: 401, msg: '재로그인 해주세요' });
            }
            //둘다 유효한 경우에는 기존의 accessToken을 넘겨줍니다.
            res.header('AccessToken', "Bearer " + accessToken);

            return next();
        } catch (error) {
        	//둘다 만료인 경우에는 에러
            error.status = 500;
            error.msg = 'token is not found';
            next(error);
        }
    }
}

 

 

 

플로우

코드를 작성해 나가면서 위의 플로우처럼 모든 시나리오를 수행하는 방법도 있을 수 있지만, 다른 방법이 있지 않을까라는 생각이 들었습니다.  

예를 들어, 토큰이 만료되었다고 클라이언트 측에서 재발급 요청을 한다거나 하는 그런 플로우도 가능하지 않을까 생각을 했습니다.
하지만, 그렇게되면 불필요한 요청이 많아지는 것을 확인할 수 있었습니다.

상황 

MySQL 1251 Error

My Code

app.use(express.json());
const connection = mysql.createConnection({ dbconfig });
connection.query('SELECT * from User', (error, rows, fields) => {
    if (error) throw error;
    console.log('User info is: ', rows);
});
app.listen(PORT, () => {
    console.log(`The Server is Listening at ${PORT}`);
});

Error Code

Error: ER_NOT_SUPPORTED_AUTH_MODE: Client does not support authentication protocol requested by server; consider upgrading MySQL client
    at Handshake.Sequence._packetToError (/Users/pjh/Desktop/chatandsns/node_modules/mysql/lib/protocol/sequences/Sequence.js:47:14)
    at Handshake.ErrorPacket (/Users/pjh/Desktop/chatandsns/node_modules/mysql/lib/protocol/sequences/Handshake.js:123:18)
    at Protocol._parsePacket (/Users/pjh/Desktop/chatandsns/node_modules/mysql/lib/protocol/Protocol.js:291:23)
    at Parser._parsePacket (/Users/pjh/Desktop/chatandsns/node_modules/mysql/lib/protocol/Parser.js:433:10)
    at Parser.write (/Users/pjh/Desktop/chatandsns/node_modules/mysql/lib/protocol/Parser.js:43:10)
    at Protocol.write (/Users/pjh/Desktop/chatandsns/node_modules/mysql/lib/protocol/Protocol.js:38:16)
    at Socket.<anonymous> (/Users/pjh/Desktop/chatandsns/node_modules/mysql/lib/Connection.js:88:28)
    at Socket.<anonymous> (/Users/pjh/Desktop/chatandsns/node_modules/mysql/lib/Connection.js:526:10)
    at Socket.emit (node:events:527:28)
    at addChunk (node:internal/streams/readable:315:12)
    --------------------
    at Protocol._enqueue (/Users/pjh/Desktop/chatandsns/node_modules/mysql/lib/protocol/Protocol.js:144:48)
    at Protocol.handshake (/Users/pjh/Desktop/chatandsns/node_modules/mysql/lib/protocol/Protocol.js:51:23)
    at Connection.connect (/Users/pjh/Desktop/chatandsns/node_modules/mysql/lib/Connection.js:116:18)
    at Connection._implyConnect (/Users/pjh/Desktop/chatandsns/node_modules/mysql/lib/Connection.js:454:10)
    at Connection.query (/Users/pjh/Desktop/chatandsns/node_modules/mysql/lib/Connection.js:196:8)
    at Object.<anonymous> (/Users/pjh/Desktop/chatandsns/src/server.js:9:12)
    at Module._compile (node:internal/modules/cjs/loader:1105:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1159:10)
    at Module.load (node:internal/modules/cjs/loader:981:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12) {
  code: 'ER_NOT_SUPPORTED_AUTH_MODE',
  errno: 1251,
  sqlMessage: 'Client does not support authentication protocol requested by server; consider upgrading MySQL client',
  sqlState: '08004',
  fatal: true
}

 

 

 

이유

mysql에서 외부 접속을 허용해 주지 않고 연결을 하였기 때문에 오류가 발생하였습니다! 

 

해결 

외부 접속 허용 확인

: mysql> select host, user from mysql.user;

위의 명령어를 통해 외부 접속이 허용이 되어 있는지 확인하기!

만약 host에 localhost 이외의 주소가 없다면 외부 접속 허용이 불가능합니다.

서버와 같은 외부에서 허용하도록 하기 위해서는 host주소를 %로 지정해주면 된다.

mysql> CREATE USER '<userid>'@'%' IDENTIFIED BY 'root';

 MySQL 데이타베이스와 계정 생성하기.

mysql> GRANT ALL PRIVILEGES ON *.* TO '<userid>'@'%' WITH GRANT OPTION;

모든 db 및 테이블에 권한을 주고 로컬 및 리모트에서도 접속가능하도록 설정

mysql> FLUSH PRIVILEGES;

설정한 권한 적용 (반드시 해야 적용이 된다.)

mysql> select host, user from mysql.user;

⇒ 제대로 잘 설정 되었는지 확인.

비밀번호 플러그인 확인

: MySQL 8.0에서는 MySQL 패스워드 플러그인 “caching_sha2_password” 때문에 클라이언트 프로그램에서 에러가 발생한다.

mysql> select host, user, plugin, authentication_string from mysql.user;

 데이터베이스의 패스워드 플러그인 확인하기.

mysql> ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'root';

 플러그인을 “mysql_native_password” 플러그인으로 바꿔주기

 

참고 블로그 : [MySQL 8.0] nestjs 연동시 에러 해결 ER_NOT_SUPPORTED_AUTH_MODE: Client does not support authentication protocol requested by server; consider upgrading MySQL client

상황 
  로그인 시,  Front에 AccessToken을 전달해줬지만, 다른 페이지를 요청할 때 AccessToken이 넘어오지 않은 경우.

이유
  프론트에서 header를 설정해 주지 않았기 때문에 local storage에만 저장이 되고 전달이 되지 않았습니다.
 

해결 

axios.defaults.headers.common['Authorization'] = `Bearer ${accessToken}`;

프론트에서 서버로 토큰을 보낼때 꼭 헤더를 설정하는걸 잊지 말도록 합시다!

'개발일지 > Troubleshooting' 카테고리의 다른 글

[Faker Error]  (0) 2023.04.19

문제 설명


문제 링크

프로그래머스[Level1] 신고 결과 받기

접근 방법

(key,value) 형식의 문제로 접근함.

  1. id_list.map을 통해 userList를 key,value로 만들어 줍니다.
    => userList 는 신고당한 사람들이 key로 value에는 신고를 한 사람들을 저장해줍니다.
  2. report.map 을 통해 report로 부터 받은 string을 split 하여 가공 가능한 자료로 바꾸어 줍니다.
    => user_id,report_id 로 신고한 사람과 신고 당한 사람을 각각 분류
  3. "한 유저를 여러번 신고할 수도 있지만, 동인한 유저에 대한 신고 횟수는 1회로 처리됩니다." 의 조건을 해결
    => userList[신고당한 사람]이 신고한 사람이랑 같지 않게 조건식을 만들어 줍니다.
  4. userList(신고 당한 사람)의 length 가 k의 값과 같거나 클 때 -> 해당 userList[key]에 해당하는 value는 object 형식이기 때문에 for문이나 map을 사용하여 id_list.indexOf()를 이용해 answer인덱스에 해당하는 값을 더해줍니다.

코드

function solution(id_list, report, k) {
    const answer = new Array(id_list.length).fill(0);
    let userList = [];
    id_list.map((value)=>{
        userList[value]= [];
    })
    report.map(value=>{
        const [user_id,report_id]=value.split(' ');
        if(!userList[report_id].includes(user_id))userList[report_id].push(user_id);
    })
    for(const key in userList){
        if(userList[key].length>=k){
            userList[key].map(v=>{
                answer[id_list.indexOf(v)]++;
            })
        }
    }
    return answer;
}

문제 설명

문제 링크

[프로그래머스[Level2] 조이스틱]
(https://school.programmers.co.kr/learn/courses/30/lessons/42860)

접근 방법

  1. ▲ ▼ 알파벳 최소 이동

    name[i]번째 value - 65('A'의 아스키 코드값) 으로 값을 구하기
    알파벳의 총 개수 : 26개 / 2 를 통해 13보다 큰 값은 'Z'로 시작하는게 더 최소임

  2. ◀ ▶ 커서 최소 이동

    해결되지 않아 구글링을 통해 직접 수기로 작성하며 이해함.

코드

function solution(name) {
    // 'A'~'Z' : 65~90
    let answer = 0;
    let answer = 0; 
    const nameLength = name.length;
    let move = nameLength - 1;
    let move = nameLength - 1; //오른쪽으로 모두 이동하였을 때의 count
    for(let i=0;i<nameLength;++i){
        let howManyClickButton = name.charCodeAt(i)-65;
        if(howManyClickButton>13) howManyClickButton = (26- howManyClickButton);
        // ▲ ▼ 부분

        //name.charCodeAt(i) => name의 i번째 인덱스의 아스키 코드값 - 65('A'의 아스키 코드값) 
        let howManyClickButton = name.charCodeAt(i)-65; 
        // 알파벳의 개수 26개, 반으로 나누어 13보다 큰 값이면 'Z'부터 count하는게 더 최소.
        if(howManyClickButton>13) howManyClickButton = (26- howManyClickButton); 
        answer+=howManyClickButton;

        // ◀ ▶ 부분
        let x = i+1;
        while(x<nameLength &&name[x]=='A') x++;

        move = Math.min(move,i+nameLength-x+Math.min(i,nameLength-x));
    }
    answer+=move;
    return answer;
}

+ Recent posts