package-lock.json은 왜 필요 한가?

npm install을 이용해서 package를 인스톨하면 자동으로 package-lock.json이라는 파일이 생성된다.

용도를 몰라서 그냥 두고 있었는데, 가끔씩 이 파일이 형상관리 과정에서 충돌이 일어나 .gitignore에 추가해버렸었다.

함께 일하시는 분이 package-lock.json은 꼭 필요하다는 이야기를 해주셔서 검색을 해보니 다음과 같은 경우에 사용된다.

  1. npm의 버전의 다른 경우
  2. 의존성을 가진 패키지의 버전이 업데이터 되는 경우
  3. 의존성을 가진 패키지가 의존하는 패키지의 버전이 업데이트되는 경우

node_modules의 폴더의 스냅샷을 저장하여, 다른 곳에서 npm install 명령어를 실행시 package-lock.json에 명시된 의존 패키지들을 통해 node_modules를 만들어 낸다. 다만, package.json의 변경은 package-lock.json 보다 우선 된다.

주요 사항은 package-lock.json은 꼭 형상 관리에 포함 시켜야 한다.

그러하다

참고자료

Posted by lahuman

댓글을 달아 주세요

Broswer의 Cookie 와 localstorage 의 차이점 정리

쿠키는 오랫동안 사용된 클라이언트에 저장하는 정보이다.

로컬 스토리지는 웹 스토리지의 하나로 기본적으로 key와 value 형태이다.

웹 스토리지세션 스토리지로컬 스토리지가 존재한다.
세션 스토리지와 로컬 스토리지의 차이는 세션이 종료되는 경우 스토리지 내용의 삭제 유무이다.

쿠키와 로컬스토리지와의 가장 큰 차이점

  1. 쿠키는 서버에서 읽을수 있음
  2. 로컬 스토리지는 클라이언트에서만 읽고 쓸수 있음
  3. 쿠키는 4Kb 까지만 지원
  4. 로컬 스토리지는 5Mb 까지 지원

참고자료

Posted by lahuman

댓글을 달아 주세요

Async Await을 이용하여 처리시 catch를 처리하지 않아 response 무한 대기 현상

개인적으로 Promise, callback 보다는 async await를 많이 이용한다.

const getSomething = asycn (req, res, next) => {

    const something = await callPromiseObject();

    res.json(something);
}

이와 같이 처리시 기본적으로는 큰 문제가 없지만, callPromiseObject() 를 실행하다 오류가 발생하면 response를 전송하지 못하여 무한 대기 하는 오류가 발생한다.

해결하는 방법은 몇가지가 있는데, 그중 하나는

const getSomething = asycn (req, res, next) => {
    try{
        const something = await callPromiseObject();

        res.json(something);
    }catch(e){
        next(e);
    }
}

이와 같이 try, catch를 이용하는 것이다. 개인적으로 동일한 코드가 계속 반복되어 좋아하는 스타일은 아니다.

또 다른 방법은 Promise를 이용하거나 callback을 이용하는 방식이다.

const asyncHandler = require('express-async-handler')

express.get('/', asyncHandler(async (req, res, next) => {
    const bar = await foo.findAll();
    res.send(bar)
}))

이런 방식으로 처리 하는 것인데, 미들웨어 코드를 보면 간단하다.

const asyncUtil = fn =>
function asyncUtilWrap(...args) {
  const fnReturn = fn(...args)
  const next = args[args.length-1]
  return Promise.resolve(fnReturn).catch(next)
}

module.exports = asyncUtil

개인적으로는 미들웨어를 사용하는 방식으로 좀더 쉬운듯 하여 찾아보니 다음과 같은 모듈도 있었다.

var express = require('express')
var wrap = require('async-middleware').wrap

var app = express()

app.use(wrap(function (req, res) {
  return Promise.reject(new Error('boom!'))
}))

참고자료

Posted by lahuman

댓글을 달아 주세요

도서관에 도서 자동 요청 프로젝트

도서관에 책을 등록하는 프로그램 입니다. 기존에 JAVA로 만들어진 모듈을 nodejs로 변경 하였습니다.
JAVA 소스의 경우 selenium을 설치하고 설정해야하는 부분이 많았는데 puppeteer를 이용하면 간단하게 최소한의 설정으로 처리가 가능하다.

프로그램 설계

부천 시립 도서관에서 한달에 요청 할 수 있는 도서는 다음과 같다.

  • 상동, 심곡, 꿈빛, 책마루, 송내도서관 : 1인당 월 5권
  • 원미, 북부, 한울빛, 꿈여울도서관 : 1인당 월 20권

이에 도서 목록을 다음과 같이 TXT 파일로 작성하연 자동으로 등록 하도록 한다.

도서목록 파일 내용 샘플

도서관코드|도서명
AA|즐거운하루
AB|자동책등록프로그램

도서관 코드

2019년 부터 상동, 심곡, 꿈빛, 책마루, 송내, 동화도서관: 1인당 월 5권 으로 변경 되었습니다.

아래 내용은 2017년 기준 내용입니다.

도서관코드 도서관명 비고
AA 상동 월5권
AB 원미 월20권
AC 삼곡 월5권
AD 북부 월20권
AE 꿈빛 월5권
AF 책마루 월5권
AG 한울빛 월20권
AH 꿈여울 월20권
AI 송내 월5권
AK 도당 월20권

프로세스 순서도

프로세스 순서도

Notice

  • nodejs 필요
  • _env 를 .env 로 파일명 변경
  • .env 에 ID/PW 작성

실행 방법

# 모듈 설치
npm install

# 실행
npm run start

License

희망 도서 자동 등록 프로그램은 open source 프로그램으로 MIT 라이선스를 따릅니다.

This Request book apply is free and open source software, distributed under the MIT License. So feel free to use this program on your project without linking back to me or including a disclaimer.

Posted by lahuman

댓글을 달아 주세요

도서관에 도서 요청

도서관에 책을 등록하는 프로그램 입니다. 기존에 JAVA로 만들어진 모듈을 nodejs로 변경 하였습니다.
JAVA 소스의 경우 selenium을 설치하고 설정해야하는 부분이 많았는데 puppeteer를 이용하면 간단하게 최소한의 설정으로 처리가 가능하다.

프로그램 설계

부천 시립 도서관에서 한달에 요청 할 수 있는 도서는 다음과 같다.

  • 상동, 심곡, 꿈빛, 책마루, 송내도서관 : 1인당 월 5권
  • 원미, 북부, 한울빛, 꿈여울도서관 : 1인당 월 20권

이에 도서 목록을 다음과 같이 TXT 파일로 작성하연 자동으로 등록 하도록 한다.

도서목록 파일 내용 샘플

도서관코드|도서명
AA|즐거운하루
AB|자동책등록프로그램

도서관 코드

2019년 부터 상동, 심곡, 꿈빛, 책마루, 송내, 동화도서관: 1인당 월 5권 으로 변경 되었습니다.

아래 내용은 2017년 기준 내용입니다.

도서관코드 도서관명 비고
AA 상동 월5권
AB 원미 월20권
AC 삼곡 월5권
AD 북부 월20권
AE 꿈빛 월5권
AF 책마루 월5권
AG 한울빛 월20권
AH 꿈여울 월20권
AI 송내 월5권
AK 도당 월20권

프로세스 순서도

프로세스 순서도

Notice

  • nodejs 필요
  • _env 를 .env 로 파일명 변경
  • .env 에 ID/PW 작성

실행 방법

# 모듈 설치
npm install

# 실행
npm run start

License

희망 도서 자동 등록 프로그램은 open source 프로그램으로 MIT 라이선스를 따릅니다.

This Request book apply is free and open source software, distributed under the MIT License. So feel free to use this program on your project without linking back to me or including a disclaimer.

Posted by lahuman

댓글을 달아 주세요

express에서 File Upload 구현 하기

업로드는 복잡하게 구현 하지 않고 모듈을 사용하면 쉽게 할 수 있다.

express-fileupload를 이용하면 된다.

# express 의 app.js 에서 다음과 같이 사용 
const fileUpload = require('express-fileupload');
const cors = require('cors');
const fs = require('fs');

app.use(cors());
app.use(fileUpload());

app.post('/upload', (req, res, next) => {
  let uploadFile = req.files.file
  const fileName = req.files.file.name
  uploadFile.mv(
    `${__dirname}/public/files/${fileName}`,
    function (err) {
      if (err) {
        return res.status(500).send(err);
      }

      res.json(JSON.parse(fs.readFileSync(`${__dirname}/public/files/${fileName}`, 'utf8')));
    }
  );
})

그게 어렵지 않게 한다.

참고자료

Posted by lahuman

댓글을 달아 주세요

google docs Sheets 연동 하기

이번에 진행되는 프로젝트에서 데이터를 Google Docs의 Sheets에 넣어 두고 해당 데이터를 활용하여 대시보드를 구현하게 되었다.

Google Sheets API 소개에도 잘 나와 있듯이, API를 활용하여 쉽게 이용할 수 있다.

Node.js Quickstart에서 제공되는 소스는 아래와 같다.

const fs = require('fs');
const readline = require('readline');
const {google} = require('googleapis');

// If modifying these scopes, delete token.json.
const SCOPES = ['https://www.googleapis.com/auth/spreadsheets.readonly'];
// The file token.json stores the user's access and refresh tokens, and is
// created automatically when the authorization flow completes for the first
// time.
const TOKEN_PATH = 'token.json';

// Load client secrets from a local file.
fs.readFile('credentials.json', (err, content) => {
  if (err) return console.log('Error loading client secret file:', err);
  // Authorize a client with credentials, then call the Google Sheets API.
  authorize(JSON.parse(content), listMajors);
});

/**
 * Create an OAuth2 client with the given credentials, and then execute the
 * given callback function.
 * @param {Object} credentials The authorization client credentials.
 * @param {function} callback The callback to call with the authorized client.
 */
function authorize(credentials, callback) {
  const {client_secret, client_id, redirect_uris} = credentials.installed;
  const oAuth2Client = new google.auth.OAuth2(
      client_id, client_secret, redirect_uris[0]);

  // Check if we have previously stored a token.
  fs.readFile(TOKEN_PATH, (err, token) => {
    if (err) return getNewToken(oAuth2Client, callback);
    oAuth2Client.setCredentials(JSON.parse(token));
    callback(oAuth2Client);
  });
}

/**
 * Get and store new token after prompting for user authorization, and then
 * execute the given callback with the authorized OAuth2 client.
 * @param {google.auth.OAuth2} oAuth2Client The OAuth2 client to get token for.
 * @param {getEventsCallback} callback The callback for the authorized client.
 */
function getNewToken(oAuth2Client, callback) {
  const authUrl = oAuth2Client.generateAuthUrl({
    access_type: 'offline',
    scope: SCOPES,
  });
  console.log('Authorize this app by visiting this url:', authUrl);
  const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
  });
  rl.question('Enter the code from that page here: ', (code) => {
    rl.close();
    oAuth2Client.getToken(code, (err, token) => {
      if (err) return console.error('Error while trying to retrieve access token', err);
      oAuth2Client.setCredentials(token);
      // Store the token to disk for later program executions
      fs.writeFile(TOKEN_PATH, JSON.stringify(token), (err) => {
        if (err) return console.error(err);
        console.log('Token stored to', TOKEN_PATH);
      });
      callback(oAuth2Client);
    });
  });
}

/**
 * Prints the names and majors of students in a sample spreadsheet:
 * @see https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms/edit
 * @param {google.auth.OAuth2} auth The authenticated Google OAuth client.
 */
function listMajors(auth) {
  const sheets = google.sheets({version: 'v4', auth});
  sheets.spreadsheets.values.get({
    spreadsheetId: '1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms',
    range: 'Class Data!A2:E',
  }, (err, res) => {
    if (err) return console.log('The API returned an error: ' + err);
    const rows = res.data.values;
    if (rows.length) {
      console.log('Name, Major:');
      // Print columns A and E, which correspond to indices 0 and 4.
      rows.map((row) => {
        console.log(`${row[0]}, ${row[4]}`);
      });
    } else {
      console.log('No data found.');
    }
  });
}

참 좋은 세상이다!

참고자료

Posted by lahuman

댓글을 달아 주세요

NodeJs에서 Parse Error: HPE_HEADER_OVERFLOW 발생

x-ray(node moudle)를 이용해서 크롤링을 개발하고 있던 중, 다음과 같은 오류를 만나게 되었다.

(node:63533) UnhandledPromiseRejectionWarning: Error: Parse Error
    at Socket.socketOnData (_http_client.js:442:20)
    at Socket.emit (events.js:189:13)
    at addChunk (_stream_readable.js:284:12)
    at readableAddChunk (_stream_readable.js:265:11)
    at Socket.Readable.push (_stream_readable.js:220:10)
    at TCP.onStreamRead (internal/stream_base_commons.js:94:17)
     bytesParsed: 6545,
  code: 'HPE_HEADER_OVERFLOW',

이 오류는 3개의 사이트중 1개의 사이트에서만 발생하였다.

원인을 파악하기 위해 검색을 하다 다음과 같은 내용을 확인하였다.

Node.js의 http 80KB의 Header 크기 제한을 가지고 있고 만약 큰 Header 크기가 필요 하다면, 명령을 실행시 특정 argument를 추가 해야 한다.

해결책은 다음과 같다!

실행하는 node 명령와 함께 --max-http-header-size=크기 argument를 추가 해라

예제)

$> node --max-http-header-size=81000 app.js

에러가 안날때 까지 최대 http header 크기를 키우면 된다.

근데... 이건 에러나는 사이트가 문제 아닌가? 80KB를 넘는 헤더를 왜 넘기지??

참고자료

Posted by lahuman

댓글을 달아 주세요

nodejs package.json의 모듈 업데이트 하기!

npm-check-updates을 이용하여 package.json에 등록된 모듈들을 의존성에 알맞게 최신 버젼으로 업데이트 할 수 있다.

설치 후 실행은 다음과 같다.

# global로 npm-check-updates 설치
$> npm i -g npm-check-updates
# 프로젝트(package.json과 동일한) 디렉토리에서 다음 명령어 실행
$> ncu -u
Upgrading /Users/admin/myProject/package.json
[====================] 17/17 100%

 app-root-path     ^2.1.0  →   ^2.2.1
 cookie-parser     ~1.4.3  →   ~1.4.4
 debug             ~2.6.9  →   ~4.1.1
 dotenv            ^7.0.0  →   ^8.0.0
 express          ~4.16.0  →  ~4.16.4
 express-session  ^1.15.6  →  ^1.16.1
 helmet           ^3.16.0  →  ^3.17.0
 http-errors       ~1.6.2  →   ~1.7.2
 morgan            ~1.9.0  →   ~1.9.1
 puppeteer        ^1.13.0  →  ^1.15.0

Run npm install to install new versions.

# 업데이트된 결과를 설치
$> npm install

자주는 아니더라도, 가끔씩은 모듈을 업데이트 하자!

참고자료

Posted by lahuman

댓글을 달아 주세요

nodejs port forwarding 처리

https를 설정하고 나니, 기존 80 포트로 요청이 있을 경우, 443으로 redirect 하는 방법을 찾아보았다.

구글을 확인해보니, 다음과 같이 쉽게 처리 할 수 있었다.

// Redirect from http port 80 to https
var http = require('http');
http.createServer(function (req, res) {
    res.writeHead(301, { "Location": "https://" + req.headers['host'] + req.url });
    res.end();
}).listen(80);

구글과 함께면 뭐든 쉽다.

참조 링크

Posted by lahuman

댓글을 달아 주세요