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
25 Aug 2017
|
springboot
deploy
gradle
troubleshooting
로컬환경에서 gradle bootRun을 통해 멀쩡하게 돌아가던 서버가 Tomcat WAS에 올렸더니 별다른 ERROR Log도 없이 모든 페이지가 404로 떴습니다.
혹시나 싶어 deploy path에 html파일 하나 만들어놓고 접근해보니 멀쩡하게 페이지가 나오더군요.
멘붕에 빠져 이것저것 건드리다가 신규 Tomcat버전의 문제인가, 신규 SpringBoot버전의 문제인가까지 찾던 도중 catalina log에서 아래와 같은 특이한 메시지를 찾았습니다.
Info : No Spring WebApplicationInitializer types detected on classpath
(이런 중요한 정보가 INFO라니…)
WAS가 SpringBoot의 WAR파일을 인식하긴 했지만 WebApplicationInitializer를 찾지 못한 것이였는데
원인을 찾으려 또 별의 별 삽질을 하며 직접 main-class도 지정하고 구글링하니 Java Version 체크해보라고도 하고
거의 반나절을 헤메다가 원인을 찾았습니다.
SpringBoot Devtools을 사용하기 위해 dependencies에 걸어 두었는데 외부 WAS에 배포할때는 해당 설정을 다 빼고 배포하면 참조 안하겠다 싶어 providedCompile
로 설정하고 application.yml에서 관련 설정을 빼고 배포했으나 이게 WAR로 배포되면서 오류를 발생시켰던 모양입니다.
해당 설정만 compile
로 변경하였더니 잘 동작합니다.
// build.gradle
dependencies {
providedCompile("org.springframework.boot:spring-boot-devtools") // ( X )
compile("org.springframework.boot:spring-boot-devtools") // ( O )
}
외부 WAS에서 오류 없이 SpringBoot Container가 올라오지 않는다면 provided
로 설정한 값 중 문제가 있는건 없는지 확인부터 해 보면 좋습니다.
22 Aug 2017
|
instanceof
class
간단하게 instanceof
는 특정 Object가 어떤 클래스/인터페이스를 상속/구현했는지를 체크하며
Class.isAssignableFrom()
은 특정 Class가 어떤 클래스/인터페이스를 상속/구현했는지 체크합니다.
// instanceof
MacPro obj = new MacPro();
if (obj instanceof Computer) {
...
}
// Class.isAssignableFrom()
if (Computer.class.isAssignableFrom(MacPro.class)) {
...
}
참고
instanceof랑 Class.isAssignableFrom(…)의 차이가 뭐죠?