Spring boot는 일반적으로 사용되는 Spring Project와 몇가지 차이점이 있다.


 일단 프로젝트의 목적 자체의 차이가 조금 있는데, Spring boot의 경우 웹 컨테이너(Tomcat)를 내장하고 있고 최소한의 설정으로 쉽게 Spring Application 을 만들기 위한 목적으로 설계된 프레임워크 내의 플랫폼이라 할 수 있다.

 그렇기 때문에 Spring boot로 Set up 할 경우 편리하게 Dependency 문제가 해결되고, 빠르게 웹 어플리케이션을 만들 수 있는 장점이 있다. 심지어 starter-pack 이라는 dependency 를 통해 아주 간단하게 웹 어플리케이션을 만들 수 있다.


 반면 Spring-boot 위에서 동작하기 때문에 확장성 등의 고려에 있어서 모든 부분을 직접 설정해주어야 하는 Spring Project 가 더 이점이 있다고 할 수 있다.

 아직까지는 비즈니스 영역에 있어서 Spring Project 가 사용되고 있지만 점차적으로 Spring-boot 가 사용될 것으로 보인다.


 Spring boot 는 또한 최근에 발생한 기술이기 때문에 여러가지 버전 호환 문제가 아직 존재한다.

Java 버전으로는6부터 지원을 하지만 Spring boot 버전에 따라서 특히 REST나 JPA의이용을위해 Spring boot 1.4 이상의 버전을 필요로 한다.


 이 때 Spring boot의 버전에 따라 내장 톰캣의 버전에 차이가 생기게 된다. 가령 Spring boot 1.2.4 이상의 버전에서는 내장 Tomcat8 이 사용되고 그 이하 버전에서는 Tomcat7 이 사용된다.


 그렇기 때문에 각 버전간 호환을 맞춰주는 수고로움이 들게 된다. 그렇지 않으면 Tomcat의 버전별 LifeCycle 에러를 맞보게 된다.

 Spring boot는 기본으로 설정된 Embed 톰캣 사용 설정을 하지 않게 명시하여 외장 톰캣을 사용할 수도 있다.



- 내용 계속 추가 예정인 포스팅입니다. - 


 OpenID와 Oauth 모두 인증을 위한 오픈 스탠더드 프로토콜로, 이를 이용하면, Facebook과 같은 인터넷 서비스의 기능을 다른 어플리케이션 등에서도 사용할 수 있다.


OAuth 사용 이전에도 다른 어플리케이션에 사용자의 아이디와 암호가 노출되지 않도록 하는 API 접근 위임이 가능한 여러 접근 방법이 있었지만 서로 통일되어있지 않았었고, 표준으로써 제정된 것이 OpenID와 Oauth 인증방식이다.


 OpenID와 Oauth 방식은 몇가지 공통점과 차이점을 갖고 있다. 일단 알아야 할 것은 두방식 모두 로그인과는 조금 다른 권한이라는 것을 의미하는 것이다.


 그 중에서도 OpenID의 주요 목적이 인증(Authentication)이라면 OAuth의 주요 목적은 허가(Authorization)이다.


 OpenID는 Login과는 다르지만 본질적으로 볼때는 로그인하는 행동과 같다. OpenID Provider로부터 사용자의 인증과정을 처리하며 Relying Party(여러 서비스)가 OpenID Provider에게 인증을 위임하는 것이다.


 물론 OAuth에도 인증 절차가 있지만 OAuth의 근본적인 목적은 해당 API를 사용할 수 있는 권한이 있는 사용자인지를 확인하는 것이다. 물론 OAuth를 사용자 인증의 방법으로 사용할 수는 있지만 근본적은 목적 자체가 다르다.


 


 아래는 Oauth 인증과정을 그림으로 표현한 것이다.

 

<원본 : http://oauth.net/core/diagram.png>


이를 정리하면 OAuth의 인증과정은 간단히 다음과 같다.


1. Request Token의 요청과 발급


2. 사용자 인증 페이지 호출


3. 사용자 로그인 완료


4. 사용자의 권한 요청 및 수락


5. Access Token 발급


6. Access Token을 이용해서 서비스 정보를 요청



OAuth 인증 방식은 단순히 기능 사용에 대한 인증을 부여하는 방식이고 그 외에 어떤 권한도 부여하지 않는다.
즉 기능 사용만을 위한 최소한의 효율적인 보안을 유지하는 방식이다.

OAuth 방식을 사용하면, 실제 보안 채널을 유지하는 것보다 개발 비용과 운영 비용을 줄이는 효과가 있으며 서비스적인 입장으로써는 타서비스에 연동함으로써 유저의 진입을 좀 더 쉽게 기획할 수도 있다.
이러한 비용적 효율성들덕분에 OAuth 인증 방식으로 패러다임이 많이 전환되어있는 추세이다.


출처 : 

https://d2.naver.com/helloworld/24942 

http://oauth.net


 실무에서 REST API 설계를 처음 다뤄보았을 때, 부족한 점들이 많이 있었다. 

많이 혼나고 나서 너무나도 좋은 글을 찾아 정리해두었다.


원본 출처는 다음과 같으며, 아래 내용은 한글로 알아보기 쉽게 정리해 놓은 부분이다.

(https://blog.mwaysolutions.com/2014/06/05/10-best-practices-for-better-restful-api/)



 RESTful Service API 의 설계 업무를 하던 중 처음에 칭찬받아서 대충 설계하다가 다시 공부하게 된 내용.

일반적으로 커뮤니케이션과 개발에 원활한 설계를 하기 위한 10가지의 방법이 존재하며 다음과 같이 서술된다.


(1) Use nouns but no verbs (동사가 아닌 명사를 통한 API 설계를 할것.)


- 가장 초보적인 실수가 CRUD 에 대한 기능을 Path에 명시하는 것이다.

 예를들어 /getAllCars, /createNewCar, /deleteAllCars 와 같은 방식인데, REST 디자인을 위해서는 CRUD 를 Method 를 이용하며 표현하기 때문에 그 외의 것은 전부 entity를 명시하는 명사로 표기한다.


 따라서 예시는 다음과 같이 HttpRequest Method를 통해서 기능이 구분되어야 한다.




 이 원칙은 표준 웹의 REST API 대부분에서 따르는 원칙이며, GET / POST / PUT / DELETE 외의 Method 들, 가령 HEAD 나 TRACE 등, 의 경우 별도의 원칙을 갖고있지 않다.



(2) GET method and query parameters should not alter the state


 역시 위에 명시한 바와 마찬가지로 모든 Functioning 은 Method로 하고 query parameter 역시 state change 등의 기능으로 사용하지 않는다.

(ex) GET /users/811?activate or GET /users/811/activate ---         (X)



(3) Use plural nouns


 path는 entity 항목을 나타내므로 복수형을 쓰고 특정하게 지정하고 싶다면 다음 Path에서 {항목} 으로 지정해준다.

(ex) GET /cars/{carName}            -- cars 와 같이 path 는 복수형. 뒤에 {carName} 으로 단수 객체 모델을 가져온다.



(4) Use sub-resources for relations


 리소스는 관계에 따른 계층형 구조를 유지한다.


(ex) GET /cars/811/drivers/ > 차811 의 드라이버 리스트를 반환한다.

(ex) GET /cars/811/drivers/4 > 차 811의 4번 드라이버 정보를 반환.



(5) Use HTTP headers for serialization formats


 서버와 클라이언트 간 커뮤니케이션에 있어서 Header Serialization format을 이용한다.



(6) Use HATEOAS


 HATEOAS 란 Hypermedia As The Engine Of Application State 의 약자로, 하이퍼텍스트 링크를 데이터 내에 명시할 경우 API를 통해 갈 수 있는 navigator 형태로 표기해준다.


<HATEOAS 의 예시. links 하위의 href 를 주목하자>


 위의 예시에서 drivers.links.href 항목은 주소를 저장함으로써, 외부주소에 저장된 리소스 자체를 가리키고 있다.

REST API 는 이런식으로 실제 리소스를 담는 것이 아닌 경로를 담아서 HyperMedia 컨텐츠를 기록한다.


 이렇게하면 네트워크 비용도 절감되고, 성능면에서도 많은 이점을 갖는다. 물론, 해당 주소로 다시 접근하여 실제 리소스를 받아와야 하는 점이 있지만, 오히려 리소스를 CDN 등을 이용한 static 저장소에 두고 가져온다면 네트워크 비용 측면에서도 훨씬 저렴하고 뛰어난 성능으로 핸들링할 수 있다.



(7) Provide filtering, sorting, field selection and paging for collections


 Filtering 은 특수한 query parameter 를 조건으로 주었을 때 해당 기능을 제공할 수 있게끔 하는 것이다.

(ex) GET /cars?color=red


 Sorting 은 오름차순, 내림차순의 정렬을 multiple field 에 대해 허용하는 것이다. 

(ex) GET /cars?sort=-name, +price > -(ascending) +(descending)


 Field selection 은 select 조건문과 같이 필드만 추출해서 보여줄 수 있도록 하는것으로, 네트워크 트래픽 관리에 효과적이다. 

(ex) GET /cars?fields=name, price


 Paging 은 Offset과 Limit 을 지정할 수 있는 조건으로 DB 조회에 필수적인 기능이다. (ex) GET /cars?offset=10&limit=5



(8) Version your API


 REST API는 Version 을 명기한다. (ex) /blog/api/v1



(9) Handle Errors with HTTP status codes


 에러는 별도의 로직으로 처리한다기 보다 HTTP 상태 코드와 메시지를 통해 처리하는 것이 좋다. 다음은 서버에서 반환하는 표준 HTTP 응답 코드를 설명한다.



에러에 따른 Payload 도 다음과 같이 명시한다.




(10) Allow overriding HTTP method


 몇몇 프록시 서버의 경우 POST와 GET 만을 지원하는 경우가 있다.

이러한 한계점을 지원하기 위해 API 단에서 override HTTP method 를 지원해줄 필요가 있다. X-HTTP-Method-Override 와 같은 Custom HTTP 헤더를 만들어 method 방식을 지원하자.






HTTP는 현재 세계에서 가장 널리 쓰이는 프로토콜 중 하나이다. 우리가 보통 사용하는 인터넷을 위한 기본 프로토콜이기도 하며, 최근래에는 다루는 기술도 비약적으로 발전하여, 예전에 웹의 영역이 아니라고 불렸던 게임 영역, 실시간 대용량 처리, 대용량 메시지 처리 등에서도 HTTP 기반의 웹 스택을 사용하는 경우를 흔히 몰 수 있다.


HTTP TCP 계층의 위에 HTTP 프로토콜 스택을 쌓아올린 Network Layer로 현재 가장 널리 사용되고 있는 Stateless / Connectless 형식의 프로토콜이다.


 여기서 Stateless 란, TCP와 다르게 상호간의 연결된 소켓이 연결을 유지하지 않는다는 의미이다.

 즉, 서로 요청과 응답만 처리하고 "상태" 는 기록하지 않는다. 서로 간에 지속적인 "연결" 이 유지되지 않기때문에 지속적이면서 연속적인 통신에는 적합하지 않다. 일반적으로 채팅 서비스를 구현할때 HTTP가 고려되지 않는 이유이기도 하다.


 대신에 단순한 정보 전달에 있어서는 가장 효율적인 프로토콜이라고 봐도 무방하다. 요청한대로 응답만 보내주면 되기 때문에, 서버 입장에서도 연결 관리에 대한 부담이 덜어지고, 클라이언트 측면에서도 원하는 정보만 얻을 수 있으므로 효율적이다.


 HTTP 역시 네트워크 프로그래밍이기 때문에 당연히 소켓을 이용하여 통신을 하게 되며, HTTP를 서비스하는 웹서버는 특유의 성질을 구현하기 위하여 일반적인 TCP 서버 등과는 다른 HTTP 프로토콜에 특화된 형태를 취하게 된다.


소켓을 이용하여 RAW한 방식으로 HTTP 웹서버를 구축할 때는 연결이 시작된 이후에(Accept) 바로 해당 소켓의 연결이 요청(Request)을 받고, 응답(Response)한 후에 연결이 끊어지게 만드는 것을 잊지 않아야 한다.


 HTTP URI Method 등을 기반으로 작동하게 된다.

 HTTP 프로토콜은 별다른 것이 있는 것이 아니라 말그대로 Socket 의 통신 버퍼에 특유의 프로토콜 스택을 쌓아올리는 것을 말한다. 다음은 요청과 응답에 따른 프로토콜 형태이다.

 

<HTTP Request Header>


 위의 요청 포맷에서 첫번째 라인은 Request Line이라고 해서 요청에 대한 포맷 정보를 명시하는 필수 요소이다. 해당 라인은 3가지의 필드로 이루어져 있으며 각 필드는 다음을 명시한다.


(1)  요청 메서드 : GET, POST, OPTIONS(UPDATE, DELETE), PUSH 등의 요청 방식이 온다.


(2)  요청 URI : 요청하는 자원의 위치를 명시한다.


(3)  HTTP 프로토콜 버전 : 프로토콜의 버전으로 1.0 1.1이 있다.



그 아래로 요청 헤더의 내용이 CRLF Delimeter로 하여 열거된다.

General Header : Cache-Control, Connection, Date, Pragma, Trailer, Transfer-Enco, Upgrade, Via, Warning

Request Header : Accept, Accept-Charset, Accept-Encoding, Accept-Language, Authorization, Expect, From, Host, If-Match, If-Modified-Since, If-None-Match, If-Range, If-Unmodified-Since, Max-Forwards, Proxy-Authorization, Range, Referer, TE, User-Agent

Entity Header : Allow, Content-Encoding, Content-Language, Content-Length, Content-Location, Content-MD5, Content-Range, Content-Type, Expires, Last-Modified, extension-header

요청 헤더의 내용이 전부 명시가 된 이후에는 Message Body두 개의 CRLF 아래에 명시된다. 두개의 CRLF 뒤에는 Request Body 가 포함되게 되며, 이부분은 HTTP 스펙에 따라서 해석의 여부가 나뉜다. (이부분은 REST API 소개 및 HTTP Method 분석 포스팅에서 자세히 다루겠다.)


 다음은 응답 헤더의 모습이다.


<HTTP Response Header>

 

첫번째 라인은 요청헤더의 Request Line 처럼 Response Header에서는 Status Line 이라 불리며 필수 정보를 포함한다.


(1)  응답 프로토콜과 버전 : HTTP/1.0, HTTP/1.1, HTTP/2.0 이 현재 버전으로 존재한다.


(2)  응답 코드 : 1xx, 2xx, 3xx, 4xx, 5xx 등의 번호가 응답 코드로 사용된다.


(3)  응답 메시지 : OK, Not Found, Internal Server Error 등의 메시지를 출력한다.


 역시 해당 라인 아래에 응답 헤더의 내용들이 포함되는데, Accept-Range, Age, Etag, Location, Proxy-Authenticate, Retry-After, Server, Vary, WWW-Authenticate 등의 정보가 포함된다. 이후에 두 개의 CRLF 라인 다음에 Message Body 가 첨부된다.

 


 복잡해보이지만 내부 구성원리는 간단하다. 

일반적인 TCP 서버를 구성하고, 프로토콜을 만드는데, 클라이언트로부터 요청을 받아서 해석하는 부분에 Request Parser를, 서버쪽에서 처리를 마치고 클라이언트에 응답을 내려줄 부분에 Response Builder 를 메시지의 머리에 붙여주면 된다.


 그렇게만 하면 웹서버가 HTTP Speculation 상에 약속한대로 메시지를 해석한다. 그렇다면 웹서버 작동의 기본 로직을 정리해보자.


(1) TCP 소켓을 열어 클라이언트의 접속을 받는다. (Accept)


(2) 커넥션을 관리할 수 있는 객체를 만들어, 쓰레드에 할당한다.


(3) 쓰레드가 해당 커넥션에 대해 HTTP Request 를 분석한다. Method 에 따라 서버 내에서 url Handler 를 라우팅해주고, 해당 라우터 메서드에서 요청에 대한 로직을 구현한다.


(4) 로직에 따라 구현한 HTTP Response 를 클라이언트에 반환하고, 접속을 끊는다. (Stateless)



좀 더 내부 동작 원리가 궁금하다면 자세한 예제는 다음 소스를 확인하면 도움이 될 것이다. 오래전에 작성한 소스라 허접하지만 웹서버 구현에 있어 기본에 충실한 좋은 예제라고 생각한다.

(https://github.com/ParkJinSang/Jinseng-Server)





P2P 는 관심있게 보고있는 기술 중 하나이다. 본 포스팅은 P2P 특징과 연결을 위한 기술들을 기술한다.


P2P 기술 개요


 P2P 기술이란 Peer To Peer 의 약자로, 소수의 서버에 집중되는 형태의 네트워크가 아닌 구성원들의 대역폭에 의존하는 다대다 통신망 기술이다. 여기서 언급하는 Peer 란 하나이자 모든 네트워크 구성요소를 말하며 모든 Peer 가 서버이자 클라이언트가 될 수 있는 구조를 지향한다. 최근에는 그리드 컴퓨팅과 그 이상의 블록체인의 기반 기술로 진화해나가고 있는 기술이다.


P2P 의 특징


 IP 네트워크는 IP주소만 알고 있으면 어떠한 단말기에도 도달할 수 있다. 인터넷에서 P2P 응용기술은 IP 네트워크 오버레이 네트워크(Overlay Network : OLN)라고 볼 수 있다. P2P는 모든 단말이 동일하지만 특별한 기능과 역할을 가진 단말이 존재하지 않으므로 연결하는 사용자수가 방대하게 되어도 특정 단말에 부하가 집중(확장성이 높은 신뢰성)한다. 즉, 더 많은 단말기로 전달이 가능하게 된다. 반면 SC 모델(Server-Client 모델)의 경우 클라이언트의 수가 증가함에 따라 서버의 처리 능력 및 서버에 연결되어있는 네트워크 회선에 부하가 집중되게 된다.(확장성이 낮다) 이에 따라서 서버 회선 비용도 크게 절감할 수 있다. 


 P2P 방식은 통신 상대 특정에 있어서 곤란한 문제를 갖고 있다. 통신상대의 IP 주소를 확인 하는 방법을 마련할 필요가 있는 것이다. 또한 통신 경로에 의한 통신 속도의 제한이 발생하게 된다. 하지만 모든 단말간 회선 품질이 동일함을 보장하는 것은 인터넷에서 불가능한 요구이다. SC 모델이 클라이언트들에 대해서 가능한한 빠른 회선 서버에 연결하도록 설계할 수 있는 반면에 P2P 방식은 그렇지 않기 때문에 회선 망에 있어서 장애를 가져올 수 있다. 


P2P 연결을 위한 기술들

 

 P2P 연결을 위해선 기본적으로 네트워크 망에 대한 이해가 필수적이다. 전통적인 서버-클라이언트 모델이 아니기 때문에, 다음과 같은 테크닉(?) 을 이용해서 연결 구조를 형성한다.


- Relaying : ClientA와 ClientB가 통신을 하는데 있어서 경우에 따라 NAT(Network Address Translation) 하에 놓일 수 있다. 이들의 통신을 중계하기 위해서 중계서버를 두고 서버를 통해 통신하는 방식이다. 접속이 유효한 동안 계속 주고받을 수 있으나 불필요한 대역폭의 낭비와 서버의 리소스를 소모하게 된다. 


- Connection Reversal : 하나의 클라이언트가 NAT 뒤에 위치하는 경우 B가 A로 연결을 시도할 때, A의 사설 IP로는 당연히 접속이 불가능하고, 서버 S가 관찰하는 NAT의 공인 IP로의 접속은 A에서 나가는 것만 허용하기 때문에 역시 접속이 불가능하다. 그래서 중계 서버 S를 이용해서 B의 공인 IP를 서버 S에게 알려준 다음 역으로 A가 접속을 시도하여 커넥션을 맺게 한다. 


- UDP Hole punching : 두 개의 클라이언트가 전부 각각의 NAT 뒤에 위치한 경우이다. 이 경우에는 두 클라이언트가 같은 NAT 뒤에 있는가 혹은 다른 NAT 뒤에 있는가로 경우가 분류된다. 


두 클라이언트가 서로 다른 각각의 NAT 뒤에 있을 때 클라이언트 A가 클라이언트 B와 연결을 맺으려면 중계서버 S를 이용해야 한다. S에 접속할 때 서버는 클라이언트 A의 정보(사설 및 공인 IP)를 취득하여 저장하게 되고 B가 접속할 때도 이 정보를 저장하게 된다. 만약 A가 B에 대해 연결을 요청하게 되면 S는 A와 B에게 동시에 서로의 IP 정보를 보내주게 되고 각 클라이언트는 이를 통해 각각 연결시도를 하게 되어 커넥션이 맺어질 수 있게 된다. 




SSL 이란 Security Socket Layer 의 약자로  Netscape에서 서버와 브라우저 간 보안을 위해 만든 프로토콜이다. SSL은 CA(Certificate Authority)라 불리는 서드 파티로부터 서버와 클라이언트의 인증을 하는데 사용된다. 서버와 클라이언트 간의 통신 과정은 다음과 같다.


(1) 클라이언트가 SSL로 암호화된 페이지를 요청한다(https)


(2) 서버는 Public key를 인증서와 함께 전송한다.


(3) 클라이언트는 인증서가 Trusted root CA(인증기관)로부터 서명된 것인지, 날짜 등이 유효한지를 확인한다.


(4) 인증을 확인한 클라이언트는Public key로 URL, http 데이터들과 자신의 대칭키을 암호화하여 전송한다.


(5) 서버는 인증서에 대한 Private key로 요청을 복호화하고 전달받은 대칭키로 응답을 암호화해서 전송한다.


(6) 브라우저는 대칭키로 응답을 복호화해서 사용자에게 보여준다.


 이렇게 대칭키를 공개키 암호화방식으로 암호화해서 전송한 후 대칭키로 통신하는 프로토콜을 SSL 방식이라고 한다.


 이 과정에서 사용되는 서명(Signing)이란 특정 메시지를 작성했다는 것을 인증하는 역할이다. 서명의 과정은 다음과 같다.


(1) 해쉬 생성


(2) Private key로 해쉬 암호화


(3) 암호화된 해쉬와 서명된 인증서를 메시지에 추가


(4) 받는 사람은 따로 해쉬를 생성


(5) 받은 메시지에 포함된 해쉬를 Public key를 이용해서 복호화


(6) 4, 5번 과정에서 생성된 해쉬를 비교한다.


 다음은 이 과정을 정리한 SSL 의 워크플로우를 나타낸 그림이다. 아래의 그림에서 1, 2, 3번 과정은 위의 설명 이전의 과정이 된다.



이처럼 SSL은 공개키로 대칭키를 전달하고 실제 암호화 및 해독 작업은 대칭키로 하여 비용과 안정성 측면에서 이점을 갖는 표준 보안 방식을 말한다. 공개키 암호화 방식은 대칭키 암호화 방식보다 훨씬 안정적이지만 속도가 훨씬 느리다. 


사이트에 대한 인증서 문제는 요청한 사이트가 ‘진짜’ 인지를 인증기관을 통해 검증받기 위해서 생긴다. 인증받은 신뢰할 수 있는 사이트의 경우 SSL 통신이 진행된다. 





CORS(Cross Origin Resource Sharing)


최근에는 대부분의 웹 서버가 REST API 서버를 통해 동작하며, 백엔드 개발자라면 익숙하겠지만 프론트엔드만 담당한다면 당황할 수도 있다. 실제로 처음에 본인도 웹페이지부터 서버 개발에 입문하면서 당황했던 부분이다.


웹사이트는 종종 인터넷 상의 다른 서버에 호스팅된 리소스를 요청하는 경우가 있다. 이때, 서버를 거치지 않고 Browser 단에서 직접 외부 호스트로부터 리소스를 받는 일은 서버의 보안 입장에서 유쾌한 일은 아니며, 호스팅하는 서버 입장에서도 무분별한 요청을 받게 되는 일이다. CORS는 이를 위해 보안정책을 통해 이를 제한하고자 하는 개념이다.


 CORS는 웹페이지가 리소스가 존재하는 다른 도메인으로 요청이 발생하는 것을 제한하는 규칙이다. 브라우저와 서버에서 다른 도메인과 안전하게 연결을 하고자 요청을 제약하는 규칙이다.


 이러한 정책이 생겨나게 된 배경에는 웹서버의 API 적 역할이 강화되었기 때문이다. REST API 를 소개하면서 포스팅하겠으나, 많은 종류의 Web API 는 GET을 제외한 요청들이 데이터를 변경할 수 있게끔 되어 있다. 


그렇기 때문에 GET이 아닌 다음과 같은 요청들의 경우 전처리과정(Pre-flight Request) 라 하여, HTTP 요청을 보내기 전에 먼저 OPTIONS 요청을 보내서 호스팅 서버로부터 확인 작업을 거친다.


 만약 호스팅 서버로부터 인증받은 도메인의 허가받은 요청이라면, 그다음 본 요청으로 리소스를 가져온다.


 - Pre-flight 요청이 선행되는 경우 : PUT , DELETE , CONNECT, OPTIONS, TRACE, PATCH

(POST 요청의 경우 조건적으로 특정 MIME Type에 대한 호출에 대해서 Pre-flight가 선행된다.)


 이는 브라우저에서 쉽게 확인할 수 가 있다. 브라우저는 위와 같이 GET / POST 이외의 요청에 대해 OPTIONS Request를 보내는데, 다음처럼 Origin 이라는 헤더를 Request 에 담아 보내게 되고, 서버 측에서 Response로 Access-Control-Allow-Origin 라는 헤더에 허용된 도메인을 담아 보낸다.




그렇다면 호스팅 서버의 응답 값을 같이 살펴보자





위의 예에서 해당 서버는 example.com 이라는 도메인에서 요청한 PUT, DELETE 메서드만 허용한다. 물론 example.com 에서 요청했기 때문에 위의 요청은 PUT 또는 DELETE 라면 에러를 발생시키지 않고, 해당 PUT / DELETE API 를 요청한다.


 CORS 표준은 서버가 지정한 일련의 도메인 들에 대해 정보를 읽을 수 있도록 허가하는 HTTP 헤더를 추가하여 문제를 해결한다.



 * 일반적으로 서버측에서는 요청들에 대해 Credentials 를 담아 처리하게 하며, 별도로 리소스에 대한 접근을 허용하는 Whitelist 방식으로 처리한다.



처음 서버 실무를 시작할 때, 몰랐던 내용인데 의외로 명확히 설명해주는 곳이 없었다. 당연하게들 알고있는것 같다 ㅜ


더군다나 각종 프레임워크나 영미권의 Document 들에서는 Roll the log files 와 같이 쓰면서 Log rolling 을 검색하면 정치 용어 가 등장하여 정리해두었다.


 Log rolling 이란 일정 단위로 로그파일을 재갱신하는 작업으로 Log rotation이라고도 한다. 하지만 영어적 표현으로 Roll(굴리다) 으로 할 뿐 정식 명칭은 Log Rotation 이 맞는 것으로 보인다.


 무식하게 로그를 계속 쌓아나가는 것이 아니라 일정 주기로 백업 또는 별도 처리하고 파일을 덮어쓰면서 순환시킨다. 이 때 순환의 주기는 데이터 별로 다른데, 지워도 문제가 없을 수준으로 보통 정한다.


 이를 정하는 건 역시 노하우... 대부분 크리티컬한 유저 데이터가 아닌 이상 CS 가 발생하지 않을 수준에서 정리하곤 한다.


 apache의 경우 이슈에 대해 파이프 로그를 수행한다. 좀 더 자세히 말하면 아파치 웹서버의 경우 Log가 끊기지 않게 하기 위해서 서버와 함께 파이프 Process를 동작시켜서 Process가 죽더라도 Logging이 죽지 않도록 파이프를 이용해서 순환시킨다. 


 대부분 로그를 작성 시에 Error Log에는 날짜, 시간, 심각성, IP주소, 오류문, 경로, 해결책 등을 포함시키며 포맷을 벗어나지 않게 작성한다. Access Log에는 모든 요청을 기록하며 보통 Access Log는 에러로그 보다도 Massive 한 경우가 많기 때문에 메시지 큐를 담당하는 미들웨어로 보내서 처리하는 경우가 많다. 





가끔 대화를 하다보면 은근히 웹서버(Web Server), 어플리케이션 서버(Application Server) 혹은 웹 어플리케이션 서버(Web Application Server) 간에 단어의 사용이 혼동되어 쓰이는 경우가 많다.


실제로 "웹 프로젝트" 를 한다고 했을때 많은 학생들은 물론 가끔은 실무자 조차도 더러 자신이 만든 프로젝트가 어떤 종류의 서버인지 긴가민가 여기는 때가 있다.


가령 토이 프로젝트로 게시판을 만들었을 때, 이를 웹서버 경험이 있다고 해야하는지, 아니면 웹 뷰가 없을 때 이를 App Server 라고 봐야하는지 헷갈린다거나, 실무에서 해당 웹 프로젝트 아키텍처의 일부분으로 구성된 서버로 어떤 종류의 서버가 붙어야하는지 헷갈린다면 이 문서가 도움이 될 수 있다.




<굉장히 간단히 표현한 Application Server>



먼저 Application Server란 위에 보이는 것 처럼 말그대로 서버 그자체를 나타낸다. 그림에서 보이는 것처럼, 네트워크가 연결되어있기만 하다면, 그 네트워크를 통해 서버와 Endpoint 간의 통신을 할 수 있는 Server 이다.


즉, HTTP 뿐 아니라 TCP, UDP 등 다양한 프로토콜을 전달받아 클라이언트에 다양한 서비스를 제공한다. 

당연히 복잡한 비즈니스 로직의 처리를 할 수 있으며 이에 따라 Client는 단순히 정보를 Display하는 것 이상의 동작이 자유롭다. Java 진영에서는 트랜잭션 처리, 보안 처리, 리소스 풀링, 메시징 등을 처리해주는 EJB, J2EE 등이 대표적이다. 


많은 Application Server는 단순히 Web page를 띄우는 이상을 처리한다.(DB와의 동적인 연동, 클러스터링, fail-over, 로드밸런싱 등) 대표적인 Java 진영의 예로는 레진서버, Spring framework, Expresso 등이 J2EE의 대표적인 Application Server Framework이다. 

Application Server는 엄밀히 말하면 Web Server와 Web Application Server를 포함하는 상위 개념이라고 할 수 있다.




 Web Server 는 HTTP 프로토콜을 주로 처리하는 서버이다. 즉, Web Server는 Application Server에 포함된다. 

HTTP Request를 받아 HTTP Response를 주며, Request를 처리하기 위해 Static HTML, Image 또는 JSON 등을 이용한다. JSP, 서블릿, ASP 등이 이용되어 요청에 대한 단순 응답을 반환하는 간단한 구조를 갖는다. 인터넷 발달 초기, 단순히 인터넷을 통해 문서 조회만 가능하던 시절의 HTTP 서버들은 주로 정적인 동작만 하는 Web Server 였다고 할 수 있다.


 대표적으로 Apache가 있으며, Apache는 정적인 처리에 특화된 웹서버이고, 세트로 있는 Tomcat은 Servelet Container로 정적인 데이터와 동적인 데이터 처리가 가능하지만, 주로 동적인 데이터의 처리를 하는 Web Application Server이다. 


 WAS 가 태어나게 된 배경은, 인터넷의 발달을 예로 들 수 있다. 인터넷의 편한 접근성과 HTTP 라는 단순하면서도 효율적인 프로토콜의 발달로, 인터넷을 통해 단순히 문서 조회 이상의 많은 것들을 요구하게 되었다. 


기존에 TCP / UDP 등의 프로토콜들이 처리하던 전자상거래, 파일 공유 등의 기능 들을 HTTP 로 수행하려다 보니 나타난 새로운 형태의 서버라 볼 수 있다.


 추가로 말하자면 정적인 HTTP 데이터 처리에 특화된 Web server에 동적인 데이터를 이용하게끔 하는 Container를 엮으면 WAS가 되며, WAS는 HTTP 를 이용하는 Application Server로 볼 수 있다.


이러한 미세한 차이 때문에 일반적으로 위에 언급한 Static Server 의 경우 WAS라고 말하기 보다는 Web Server 혹은 스태틱 서버 라고 표현을 많이 하고, HTTP 프로토콜을 사용하지 않는 TCP 서버 등은 WAS가 아닌 App Server 혹은 Application Server 로 표현한다.




Spring 을 공부하다보면 빠지지않고 등장하는 개념이 바로 POJO(Plain Old Java Object) 이다.


이는 정말 단순한 개념이지만, 개인적으로 Spring Framework 라는 훌륭한 프레임워크를 만들게 되는 철학의 가장 밑바탕을 구성하고 있다고 생각하는


핵심적인 개념이다. 개인적으로 공부하고자 이 글을 보게되었다면 이해하고 넘어가야한다고 생각한다.



POJO 의 개념 : 주로 특정 자바 모델이나 기능, 프레임워크를 따르지  않는 Java Object를 지칭한다.


거창해보이지만 다음 예제를 보면 간단해진다.

 


public class MyPojo {
private int name;
private int value;

public int getName() {
return name;
}
public int getValue() {
return value;
}
public void setName(int name) {
this.name = name;
}
public void setValue(int value) {
this.value = value;
}
}



그렇다 위와 같은 가장 기본적인 형태의 Java 객체를 POJO라 한다.


좀 더 자세히 명시하자면...


EJB 등에서 사용되는 Java Bean 이 아닌 Getter 와 Setter 로 구성된 가장 순수한 형태의 기본 클래스를 POJO라 하며, 이는 Spring에서 고안된 철학의 핵심적인 부분을 구성하는 요소로 사용된다



향후 포스트를 통해 언급하게 되겠지만 Spring 에서 고안된 중요한 철학은 바로 "복잡성의 해결 을 통한 생산성의 향상" 이다. 


이를 위해서 POJO 는 EJB 의 Bean 에 비해 훌륭한 객체의 단위가 될 수 있다.


그 이유로 먼저 POJO는 그 자체로 객체지향 철학이 반영된 가장 기본적인 단위의 객체이다. 


객체의 상태와 동작을 정의하는 Member variable 과 Method 를 독자적으로 가질 수 있으며 그 자체로 하나의 객체를 묘사할 수 있다. 


또한, 상속성, Interface 등의 여러가지 기술에 의해 종속되지 않는 객체이기 때문이다.  


Java가 급격히 발전해가는 비즈니스 요구를 효과적으로 만족시키고자 Enterprise Java 로 진화하면서 생겨난 EJB는 

오히려 과도한 Over engineering 때문에 객체지향 철학 자체를 효과적으로 구현할 수 없었던 아이러니를 가졌으며, 

이는 개발자들의 시선을 다시 POJO로 향하게 만들었다. 


POJO 의 단순한 구조는 Over engineering 으로 인한 복잡성을 해결하고 모듈화시킬 수 있는 부분에서 큰 이점을 가진 보다 나은 형태의 구조 였고, 이후 개발된 Spring과 같은 POJO 기반의 프레임워크 들은 이러한 이점을 살려 보다 효과적인 기술 스택으로 자리잡을 수 있었다.




+ Recent posts