NaN 이란 무엇인가?

NaN은 Not a Number ( 숫자가 아님 )을 나타낸다.

이번에 인턴일로 맡은 작업에서 NaN을 되게 많이 맞닥뜨렸는데, NaN이 무엇을 의미하는지 명확하게 몰랐었어서 난감했었다.

이번에 NaN으로 고생하기 전까지만해도 NaN의 개념을 undefiend나 null과 비슷한 개념이라고 생각을 하고 있었고, NaN인지 판단하는 로직 또한 일반적인 === (Strict equality) 연산자로 비교할 수 있는 줄 알았다.

 

내가 이번 프로젝트에서 에러사항을 겪었던 로직과 유사하게 코드를 작성해 보았다.

아래 코드의 결과는 무엇일까?

나처럼 NaN이 무엇인지 명확하게 모르거나 NaN을 처음 접해보는 사람은 당연히 "a is not number"가 출력될 것이라고 생각할 것이다.

( 아님 말고 ! )

const a = NaN;

if( a === NaN || a === undefined || a === '0' ) {
	console.log("a is not number");
}
else{
	console.log("a is number");
}

그러나 이 코드를 실제로 돌려보면 아래와 같이 "a is number"라는 결과가 나오는 것을 알 수 있다.

왜 이러한 결과가 나오는 것일까 ? 내가 원하는 결과는 "a is not number"인데 !!

처음에는 | a === NaN | 비교 구문이 문제가 있다는 것을 파악하지 못했어서 조금 시간이 걸렸었다.

디버깅 하면서 NaN을 비교하는 구문이 제대로 실행되지 않았다는 것을 파악하고, NaN에 대해 먼저 구글링해보았다.

 

MDN 문서에 따르면 NaN은 전역 스코프의 변수로, NaN의 초기값은 Not-A-Number로, Number.NaN의 값과 같다고 한다.

최신 브라우저에서 NaN은 설정 불가, 쓰기 불가 속성이라고 한다. 

 

NaN 판별

NaN은 다른 모든 값과 비교 ( == , !=, ===, !== )했을 때 같지 않으며(false), 다른 NaN과도 같지 않다.

NaN의 판별은 오로지 Number.isNaN() 또는 isNaN()을 사용해야 제일 분명하게 수행할 수 있다. 아니면 오로지 NaN만이 자기 자신과 비교했을 때 같지 않음을 이용할 수도 있다.

 

아래 예제를 통해 더 쉽게 이해할 수 있다.

NaN === NaN;        // false
Number.NaN === NaN; // false
isNaN(NaN);         // true
isNaN(Number.NaN);  // true

function valueIsNaN(v) { return v !== v; }
valueIsNaN(1);          // false
valueIsNaN(NaN);        // true
valueIsNaN(Number.NaN); // true

출처 : MDN

 

그러나 isNaN()과 Number.isNaN()의 차이점을 기억해 두어야 한다. isNaN은 현재 값이 NaN이거나, 숫자로 변환했을 때 NaN이 되면 참을 반환하지만, Number.isNaN은 현재 값이 NaN 이어야만 참을 반환한다.

const an = '8';
const nan = 'c';

console.log(isNaN(an)); // false
console.log(isNaN(nan)); // true

console.log(Number.isNaN(an)); // false
console.log(Number.isNaN(nan)); // false

 

728x90

들어가기전

기존에 Web으로 만들고 있던 tool을 exe 실행파일로 만들었으면 좋겠다는 요구사항이 추가되어, node js를 사용하여 exe파일을 만드는 방법을 이것 저것 찾아보다가 UI로 보여주는 desktop app을 만들 수 있는 Framework인 Electron 과 js 파일을 exe 실행파일로 컴파일 해주는 패키지인 pkg 라는 것을 알게 되었다. 

인턴기간이 앞으로 길게 남지 않은 만큼 가장 간단한 pkg 패키지를 사용하여 exe 실행 파일을 만들고자 하는데 여러 에러 사항에 부딪혔다. 아직 해결하지 못한 에러 사항들도 존재하지만 해결하면 바로 본 포스트에 기록할 예정이다. 


 pkg 

pkg 패키지에 대한 자세한 내용은 아래 링크에서 알 수 있다. 

pkg를 사용하면 node js가 설치 되어 있지 않은 환경에서도 실핼할 수 있는 exe 실행파일을 생성할 수 있다. 

해당 패키지를 사용하기 위해서는 아래 명령어를 통해 pkg를 설치해주어야 한다.

$ npm install -g pkg

https://github.com/vercel/pkg#readme

 

GitHub - vercel/pkg: Package your Node.js project into an executable

Package your Node.js project into an executable. Contribute to vercel/pkg development by creating an account on GitHub.

github.com

 

pkg 사용법

pkg github를 번역한 것이다.

사용사례  ( Use Cases )

  • Make a commercial version of your application without sources
    • sources 없이 나의 application의 사용 버전 만들 때
  • Make a demo/evaluation/trial version of your app without sources
    • sources 없이 나의 app의 demo/evaluation/trial 버전을 만들 때
  • Instantly make executables for other platforms (cross-compilation)
    • 다른 플랫폼을 위한 실행 파일을 즉시 만들 때 ( 크로스 컴파일 )
  • Make some kind of self-extracting archive or installer
    • 자체 풀림 압축 파일 ( 자동 압축 풀림 파일 ) 또는 설치 프로그램을 만들 때
  • No need to install Node.js and npm to run the packaged application
    • Node js, npm 설치가 필요 없이 패키지된 application을 실행하기 위해
  • No need to download hundreds of files via npm install to deploy your application. Deploy it as a single file
    • 나의 application을 배포하기 위해서 [ npm install ] 로 몇 백개의 파일들을 다운로드 할 필요 없이 단일 파일로 배포할 때
  • Put your assets inside the executable to make it even more portable
    • 휴대성/이식성을 높이기 위해 assets을 실행파일 안에 넣는다.
  • Test your app against new Node.js version without installing it
    • app 설치 없이 새로운 Node.js 버전에 대해 나의 app을 Test할 때

 

사용법 ( Usage )

$ npm install -g pkg

설치 후에 pkg --help 를 통해서 pkg의 옵션 리스트를 확인할 수 있다.

  pkg [options] <input>

  Options:

    -h, --help           output usage information // 결과 : 사용법 정보
    -v, --version        output pkg version // 결과 : pkg 버전
    -t, --targets        comma-separated list of targets (see examples) // 쉼표로 구분된 타겟의 리스트
    -c, --config         package.json or any json file with top-level config // package.json 또는 최상위 ( top - level )구성이 있는 모든 json 파일
    --options            bake v8 options into executable to run with them on // v8 옵션을 실행할 실행파일 굽기 
    -o, --output         output file name or template for several files // 결과 : 파일 이름 또는 여러(몇몇개의) 파일들의 템플릿
    --out-path           path to save output one or more executables // 하나 또는 여러개의 실행 파일 output을 저장할 경로
    -d, --debug          show more information during packaging process [off] // packaging process 동안 더 많은 정보를 보여준다.
    -b, --build          don't download prebuilt base binaries, build them // 미리 빌드된 기본 바이너리를 다운로드 하지 않고, 빌드
    --public             speed up and disclose the sources of top-level project // 최상위 프로젝트의 속도를 높이고, sources를 공개
    --public-packages    force specified packages to be considered public // 지정된 package를 public으로 고려되도록 강제 
    --no-bytecode        skip bytecode generation and include source files as plain js // bytecode 변환을 skip하고 일반 js file을 포함한다.
    --no-native-build    skip native addons build // native addons 빌드를 skip
    --no-dict            comma-separated list of packages names to ignore dictionaries. Use --no-dict * to disable all dictionaries //
    -C, --compress       [default=None] compression algorithm = Brotli or GZip // 압축 알고리즘 지정

  Examples:

  – Makes executables for Linux, macOS and Windows
    $ pkg index.js
  – Takes package.json from cwd and follows 'bin' entry
    $ pkg .
  – Makes executable for particular target machine
    $ pkg -t node14-win-arm64 index.js
  – Makes executables for target machines of your choice
    $ pkg -t node12-linux,node14-linux,node14-win index.js
  – Bakes '--expose-gc' and '--max-heap-size=34' into executable
    $ pkg --options "expose-gc,max-heap-size=34" index.js
  – Consider packageA and packageB to be public
    $ pkg --public-packages "packageA,packageB" index.js
  – Consider all packages to be public
    $ pkg --public-packages "*" index.js
  – Bakes '--expose-gc' into executable
    $ pkg --options expose-gc index.js
  – reduce size of the data packed inside the executable with GZip
    $ pkg --compress GZip index.js

 

대상 ( Targets )

pkg는 한 번에 여러 대상 시스템을 위한 실행파일을 생성할 수 있다.

--tagets 옵션을 통해서 콤마로 구분한 여러 대상 목록을 지정할 수 있다. 

3개의 요소로 구성된다.

1. nodeRange ( node8 ) , node10, node12, node14, node16

2. paltform alpine, linux, linuxstatic, win, macos,  (freebsd)

3. arch x64, arm64, ( armv6, armv7 )

(element)는 지원되지 않지만 컴파일 시도는 할 수 있다.

 

다른 아키텍처를 위한 실행파일을 생성하고자 한다면, 기본적으로 바이트코드를 생성하기 위해 pkg는 대상(target)의 실행파일을 실행해야 한다.

 

구성 ( Config )

곧 퇴근시간 이슈로 다음에 이어서 작성하도록 하겠다.

https://github.com/vercel/pkg#config

 

 


날 힘들게 하는 오류 녀석 (1) 실행 후 바로 종료 ✅

현재 나의 개발 환경은 Mac M1으로 Mac OS 환경에서 작업을 하고 있다. 인턴 업무로 주어진 프로그램을 Mac 환경에서만 주로 테스트를 하다가 최종적으로 Mac OS 환경에서 정상작동하는 것을 확인하고, Windows 환경에서 돌아가는지 확인을 해 본 결과 exe 파일을 실행하면 command 창이 켜졌다가 바로 꺼지는 현상이 발생했다. 

 

sleep을 걸어보았으나 같은 현상이 발생하였고, mac os 환경에서는 잘 되던게 갑자기 Windows에서는 동작하지 않아 많이 .. 당황스러웠다. 이 에러사항을 해결하기 위해 열심히 구글링을 해보았으나 아직 해결하지 못하였다. ( 08. 17 ~ ing ) 

 

해결하게 된다면 해결방법을 작성하러 다시 오ㅏ...야지

 

08. 24. WED

엄청나게 삽질을 하다가 돌아왔다. 

 function sleep(sec) {
    return new Promise(resolve => setTimeout(resolve, sec * 1000));
}

...

// 코드 끝자락
sleep(100).then( r =>{ console.log(r);});

위와 같은 코드를 통해서 코드 끝부분에 setTImeout으로 구현한 sleep을 걸어주었더니 실행파일이 바로 꺼지는 현상이 사라졌다. 

그러나 이번에는 경로 오류가 나를 기다리고 있었다. 

코드에서 fs.readFileSync의 모든 경로를 절대경로로 설정해주었는데, 왜 파일을 읽어오지 못하지 ? 라는 의문이 생겼고, 열심히 구글링을 한 결과 어떤 한 블로그에서 node js 는 현재 node가 실행중인 경로를 기준으로 파일을 읽어온다는 사실을 알게 되었다. 

그래서 모든 읽어와야하는 파일을 실행파일과 같은 위치에 두고 읽어오는 방식을 상대경로로 수정을 하였다. 

 

그러나 상대경로로 설정을 하여도, 같은 에러가 발생...ing... 

이번에는 경로 에러를 해결해보아야지..

728x90

들어가기전

이번에 인턴을 하면서 인증서를 검증하는 툴을 만드는 업무를 맡게 되었다..! 두둥탁 !

node.js 잘 모르지만 일단 뚱땅뚱땅 열심히 해봐야지 하고 코드 작성하는데..! 

두둥 ! client단에서 파일을 업로드하면 req.body안에 파일이 들어있을 줄 알았는데 아무것도 받아오지 못한다 !! 쿠광!

응애 개발자 결국 stackoverflow에 질문을 남기게 되는데..!

Node.js File 받아오기

file, image, 제목, 내용 등을 입력하여 DB에 저장하는 페이지가 있다고 할 때 formdata에 담아서 전송을 해야한다.

처음에는 이것도 몰라서 무작정 업로드된 파일을 body안에 넣었으나 제대로 동작하지 않았다. 

 

FormData는 XMLHttpRequest 전송을 위해 특수하게 설계된 객체이기 때문에 특정한 조작을 하지 않은 이상 문자열화가 불가능하다.

 

내 React Code는 아래와 같았다.

// React - FileUplader.js

    const handleSubmission = (e) => {
        e.preventDefault();
        if(isSelected === false){
            alert("load the file");
        }
        else{
            const formData = new FormData();
            formData.append("certificate",selectFile);

            // API CALL
            fetch("http://localhost:8080/upload", {
                method: "POST",
                body: formData,
                headers : {
                    "Content-Type" : "multipart/form-data"
                }
            }).then((response) =>response.json())
            .then((result)=>{
                console.log("Success : ", result);
            })
                .catch((error)=>{
                    console.error("Error : ",error);
                });
        }
    };

사용자가 File을 업로드하고 submit button을 누르면 "http://localhost:8080/upload"로 요청을 보낸다. 이전에 사용자가 업로드한 파일을 formdata 객체에 넣어주고, 해당 객체를 body에 넣어 전송해준다. 

 

이렇게하면 body에서 바로 받아올 수 있을 것이라고 생각했으나 ! 결과는 {} ..

아래는 내가 작성했던 server.js 코드였다.

/upload 로 post 요청이 들어오면 req.body에서 사용자가 보낸 데이터를 받아올 수 있을 것이라고 생각 했으나 결과는 {} 였다.

app.use(cors()); 
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended : true}));

app.post('/upload', async function(req ,res){
    try {
        const file = req.files; // undeifined
        const bodyData = req.body; // {}
        console.log("file : ",file);
        console.log("bodyData : ",bodyData);

        res.status(200).send({
            message: "FILE RECEIVED!"
        });
    } catch(error){
        res.send("ERROR")};
});

파일을 받아오기 위해서는 "multer" OR "express-fileupload"를 사용해야 했었다. !!!!

나는 multer를 사용하여 아래와 같이 코드를 작성하였다.

const multer = require('multer');
const upload = multer({
    dest : "public/"
});

app.post('/upload', upload.single('file'), function(req ,res) {
	// 중간코드
});

multer middleware를 사용하여 사용자로부터 받아온 파일을 public/ 폴더에 저장시킨다. 

이후 app.post ('/uploac'... ) 코드 안에 해당 저장된 파일을 다시 읽어와 처리를 하는 식으로 코드를 작성하였다.

 

아직 제대로 이해하고 짠 코드가 아니라서 다음에 더 자세히 해당 middleware에 대해 알아볼 것이다.

다음에는 express-fileupload를 사용해봐야지.

728x90

PKI ( Public Key Infrastructure )

PKI ( = 공개키 기반 구조 )는 디지털 증명서의 생성, 관리, 배포, 사용, 저장 및 파기, 공개키 암호화의 관리에 필요한 역할, 정책 등 일련의 절차들을 집합한 것이다.

통신에 관계된 당사자의 신원을 확인하고, 전송되는 정보의 유효성을 확인하기 위한 엄격한 증거가 필요한 활동에 대해 요구된다. 즉, 암호화와 복호화키로 구성된 공개키를 이용해 송수신 데이터를 암호화하고 디지털 인증서를 통해 사용자를 인증하는 시스템을 말한다.

공개키 암호의 사용화를 위해서는 무엇보다도 키의 생성과 인증이 필요하며 이런 것들에 대한 분배와 안전한 관리를 위한 체계가 필요하다. 이 시스템을 PKI라고 한다.

 

PKI는 일반적으로 인증기관(CA) 및 등록 대행 기관 (RA)을 구성한다. 

인증기관 (CA)는 아래와 같은 서비스를 제공한다.

- 디지털 인증서 발행

- 디지털 인증서 유효성 검증

- 디지털 인증서 폐기

- 공개 키 분배

 

RA는 디지털 인증서가 요청되면 제공된 정보를 확인한다. RA가 정보를 확인하면 CA가 디지털 인증서를 요청자에게 발행할 수 있다. 

 

[ + ] 더 많은 내용을 노션에 정리했지만 나중에 시간이 된다면 여기로 조금 더 정리해서 옮겨와야지 ! 

 

출처 : 

https://datatracker.ietf.org/doc/html/rfc5280

https://www.ibm.com/docs/ko/ibm-mq/7.5?topic=ssfksj-7-5-0-com-ibm-mq-sec-doc-q009900--htm  

728x90

+ Recent posts