13 Sep 2017
|
springboot
yaml
octal
문제
프로그램 버그를 잡는중 아래와 같은 문제가 생겼습니다.
# apllication.yml
tran-cd:
req: 00100000
@Value("${tran-cd.req}") private String code; // expect "00100000" but "32768"
위와 같이 해당 설정값이 이상하게 변경되어 있는 것입니다. “00100000”로 나와야하는데 자꾸 “32768”로 나옵니다.
문제는 yaml 1.1 버전에서 맨 앞자리가 “0”으로 시작하면 해당 값을 8진수로 인식하게 되고 Spring에서 @Value로 가져올 때 해당 값을 10진수로 변경하여 String 으로 반환하는 것이였습니다.
해결방법
yaml에서는 쌍따옴표(double quotes), 외따옴표(single quote)로 문자열을 쌓을수 있습니다.
#application.yml
tran-cd:
req: "00100000"
그 외
yaml문법중 %YAML 태그를 이용하여 버전을 명시 할 수 있습니다.
YAML 1.2에서는 8진수 표현법이 바뀌어서 위와 같은 오류를 막을수 있으나 application.yml에 적용해도 위 문제가 해결되지 않는 것으로 보아 SpringBoot에서 쓰는 Yaml Parser가 1.1로만 인식하나 봅니다.
해결 방법은 찾지 못했네요.
참고
%YAML 1.1 # Reference card
07 Sep 2017
|
nodejs
express
expressgenerator
처음 Node.js 개발환경을 구성 할 때 이것저것 설정할게 많은데 간단하게 “Node.js + Express”구조의 뼈대를 만들어주는 express-generator라는 도구가 있습니다.
“Java + Spring Boot” 개발환경의 뼈대를 만들어주는 Spring Initializr와 비슷한 녀석입니다.
설치
npm을 통해서 아래와 같이 설치합니다.
$ npm install -g express-generator
프로젝트 만들기
express라는 명령어로 실행이 가능한데 도움말을 보면 아래와 같이 설정을 볼 수 있습니다.
$ express -h
Usage: express [options] [dir]
Options:
-h, --help output usage information
--version output the version number
-e, --ejs add ejs engine support
--pug add pug engine support
--hbs add handlebars engine support
-H, --hogan add hogan.js engine support
-v, --view <engine> add view <engine> support (dust|ejs|hbs|hjs|jade|pug|twig|vash) (defaults to jade)
-c, --css <engine> add stylesheet <engine> support (less|stylus|compass|sass) (defaults to plain css)
--git add .gitignore
-f, --force force on non-empty directory
먼저 express를 이용하여 뼈대가 되는 소스를 만들고 해당 프로젝트 폴더 내에서 npm install을 실행하여 dependency를 다운 받고 사용하면 됩니다.
만약 template engine은 handlebars를 사용하고 css engine은 sass를 사용한다면 아래와 같이 실행하시면 됩니다.
$ express --view=hbs --css=sass <project dir>
$ cd <project dir>
$ npm install
$ npm start
기본적으로 package.json에 start커맨드를 통해 서버를 올릴 수 있도록 script를 만들어주며 실행시 http://localhost:3000으로 접속하여 동작 화면을 확인 할 수 있습니다.

app.js 파일을 열면 다음과 같이 template/css engine이 설정 되어 있는 것을 확인 할 수 있습니다.
// app.js
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'hbs');
...
app.use(sassMiddleware({
src: path.join(__dirname, 'public'),
dest: path.join(__dirname, 'public'),
indentedSyntax: true, // true = .sass and false = .scss
sourceMap: true
}));
SASS 변경하기
설정을 보면 기본적으로 sass를 사용하도록 되어 있습니다. 저는 scss확장자를 쓰고 싶으니 변경해 보도록 하겠습니다.
// app.js
app.use(sassMiddleware({
...
indentedSyntax: false, // true = .sass and false = .scss
...
}));
기본적으로 CSS경로는 /public/stylesheets 하위로 설정되어 있습니다. sass파일을 scss로 바꿉니다.
그리고 설정을 scss문법에 맞게 수정합니다.
// style.scss
body {
padding: 51px;
font: 25px "Lucida Grande", Helvetica, Arial, sans-serif;
color: #445544;
}
a {
color: #AAB7FF;
}
node-sass-middleware의 옵션 중에 css파일을 압축해주는 ‘compressed’ 옵션이 있습니다. 아래와 같이 적용해봅니다.
// app.js
app.use(sassMiddleware({
...
outputStyle: 'compressed',
...
}));
적용이 완료되고 npm start명령을 통해 서버를 실행하고 http://localhost:3000을 호출하여 다운받은 style.css파일을 확인하면 다음과 같이 변경된 것을 확인 할 수 있습니다.
css/template파일을 변경시 바로 적용되나 app.js파일 수정시에는 반드시 express server를 재시작해야 합니다.

참고
npm express-generator
npm node-sass-middleware
07 Sep 2017
|
nodejs
express
troubleshooting
webstorm
expressgenerator
Node.js로 개발해보려고 WebStorm에서 Node.js 프로젝트를 생성하다가 아래와 같은 오류를 만났습니다.
Error creating Node.js Express App. Cannot find

구글링을 해보니 답변은 express-generator를 이용하여 만든 후 WebStorm에서 해당 폴더를 오픈하여 프로젝트를 생성하라고 하더군요. (Error creating Node.js Express App. Cannot find)
생성 방법은 아래와 같습니다.
$ npm install -g express-generator
$ express <project_name>
$ cd <project_name>
$ npm install
자세한 생성 방법은 express-generator - Node.js + Express 프로젝트 생성하기를 참고하세요.
위 명령 실행 후 WebStrom에서 Open하여 사용하면 정상적으로 만들어져 있는것을 확인 할 수 있습니다.
또 다른 방법으로는 WebStorm에서 Node.js 프로젝트 생성시 사용하는 express-generator버전을 낮춰서 해결 할 수 있는데 “14.14.1”로 낮추면 정상 생성 가능합니다.

4.13.0 버전 이하로 낮출 경우 SASS를 쓸 수 없으니 주의하세요
참고
Error creating Node.js Express App. Cannot find
01 Sep 2017
|
docker
redis
Docker를 이용하여 간단하게 redis 설치 및 사용하는 방법을 정리해봤습니다.
설치
Docker가 설치 된 상태에서 아래 커맨드를 이용하여 설치합니다.
시작하기
$ docker run --name some-redis -d -p 6379:6379 redis
Docker를 실행하여 Redis서버를 올리고 기본 포트인 6379로 실행됩니다.
-d옵션은 백그라운드에서 실행하겠다는 의미이며
-p옵션은 외부에서 해당 포트로 접속할 수 있게 열어둔다는 의미입니다.
해당 Redis서버의 데이터를 외부에서 관리하고 싶을 경우에는 아래와 같이 사용합니다.
## 외부 폴더에 데이터 저장소를 두고 싶을 경우
$ docker run --name some-redis -d -v /your/dir:/data redis redis-server --appendonly yes
## 다른 컨테이너에 저장소를 두고 싶은 경우
$ docker run --name some-redis -d --volumes-from some-volume-container redis redis-server --appendonly yes
appendonly yes 옵션은 AOF방식으로 데이터를 저장(참고:Redis Persistence Introduction)하겠다는 의미입니다.
데이터는 기본적으로 /data하위에 저장되며 외부에서 해당 폴더를 공유함으로써 해당 컨테이너를 지우고 새로 만들어도 해당 volume을 참고하게 하면 동일한 데이터를 유지 할 수 있습니다.
OS X의 경우 사전에 Docker에서 공유폴더로 지정되지 않은 경우 아래와 같은 오류를 만날 수 있습니다.
docker: Error response from daemon: Mounts denied:
The path /Users/jistol/data
is not shared from OS X and is not known to Docker.
You can configure shared paths from Docker -> Preferences… -> File Sharing.
See https://docs.docker.com/docker-for-mac/osxfs/#namespaces for more info.
위와 같은 오류 발생시 메시지에 나온데로 Docker -> Preferences -> File Sharing 설정에서 공유할 폴더를 추가해 주면 됩니다.

외부에서 접근하기
외부에서 Redis 컨테이너를 접근하는 방법은 3가지 입니다.
1. 외부 서버에서 접근하기
위에 명시한 것과 같이 -p 옵션을 통해 port를 뚫어 직접 접근 할 수 있습니다.
$ docker run --name some-redis -d -p 6379:6379 redis
2. 다른 컨테이너에서 접근하기
--link나 -network옵션을 통해 접근 가능합니다. (참고:Docker container networking)
$ docker run --name some-app --link some-redis:redis -d application-that-uses-redis
3. redis-cli로 접근하기
아래와 같은 명령으로 접근할 수 있습니다.
$ docker run -it --link some-redis:redis --rm redis redis-cli -h redis -p 6379
Redis 컨테이너 기동 방식에 따라 --link나 --network, 혹은 port를 외부로 열었다면 두 옵션 없이 사용 가능합니다.
--rm 옵션은 컨테이너 종료시 자동으로 해당 컨테이너를 삭제해줍니다.
참고
library/redis - Docker Hub
Redis Persistence Introduction
Docker container networking
30 Aug 2017
|
tomcat
cookie
rfc6265
troubleshooting
증상
여러 서브도메인에서 쿠키를 공유하기 위해 .xxxx.com 같이 쿠키 도메인을 설정하는 케이스가 있습니다.
// sub domain list : sub1.xxxx.com, sub2.xxxx.com, sub3.xxxx.com
cookie.setDomain(".xxxx.com");
위와 같이 사용시 Tomcat 8버전 이상 사용할 경우 아래와 같은 에러를 만나게 됩니다.
java.lang.IllegalArgumentException: An invalid domain [.xxxx.com] was specified for this cookie
원인
tomcat 8버전 이상에서는 Cookie Header를 파싱하는 기본 CookieProcessor가 RFC6265를 기반으로 합니다. (org.apache.tomcat.util.http.Rfc6265CookieProcessor)
RFC6265의 속성중 하나는 아래와 같은데
5.2.3. The Domain Attribute
If the attribute-name case-insensitively matches the string "Domain",
the user agent MUST process the cookie-av as follows.
If the attribute-value is empty, the behavior is undefined. However,
the user agent SHOULD ignore the cookie-av entirely.
If the first character of the attribute-value string is %x2E ("."):
Let cookie-domain be the attribute-value without the leading %x2E
(".") character.
Otherwise:
Let cookie-domain be the entire attribute-value.
Convert the cookie-domain to lower case.
Append an attribute to the cookie-attribute-list with an attribute-
name of Domain and an attribute-value of cookie-domain.
Domain값 맨 앞자리에 “.”을 붙일 경우 “.”을 제거하고 파싱하게 됩니다.
해결
위와 같은 현상을 막기 위해 org.apache.tomcat.util.http.LegacyCookieProcessor 클래스를 제공합니다.
위 클래스는 RFC6265, RFC2109, RFC2616 기반으로 파싱하며 쿠키 작업의 에약을 여러 옵션을 통해 풀 수 있도록 제공하는데
Tomcat 서버 사용시 context.xml에 아래와 같이 추가해주면 됩니다.
<CookieProcessor className="org.apache.tomcat.util.http.LegacyCookieProcessor"/>
만약 SpringBoot에서 Embedded Tomcat을 사용하고 있다면 아래와 같이 설정 할 수 있습니다.
@Bean
public EmbeddedServletContainerCustomizer tomcatCustomizer() {
return container -> {
if (container instanceof TomcatEmbeddedServletContainerFactory) {
TomcatEmbeddedServletContainerFactory tomcat = (TomcatEmbeddedServletContainerFactory) container;
tomcat.addContextCustomizers(context -> context.setCookieProcessor(new LegacyCookieProcessor()));
}
};
}
참고
Apache Tomcat 8 Configuration Reference - The Cookie Processor Component
RFC 6265 - HTTP State Management Mechanism - IETF Tools
RFC 2109 - HTTP State Management Mechanism - IETF Tools
java.lang.IllegalArgumentException: An invalid domain .test.com was specified for this cookie