본문 바로가기
프로그래밍 놀이터/Web

"웹을 지탱하는 기술" 내용정리.

by 돼지왕 왕돼지 2013. 6. 24.
반응형


 "웹을 지탱하는 기술" 내용정리.

 



"웹을 지탱하는 기술" 이라는 일본 저자가 쓴 책을 본 후에,
핵심이 되는 내용이랑 내가 몰랐던 내용인데 정리해두면 좋을 것 같은 내용을 정리해본다.

설명과 함께 정확한 내용, 빠진 내용을 확인하고 싶은 사람은 책을 직접 볼 수 있도록~




웹의 다양한 용도


1. 웹사이트


2. User Interface

HTML 도움말, 웹 UI for embedded systems


3. API

Web Service 라 부름




웹을 지탱하는 기술


1. HTTP, URI, HTML


2. 하이퍼미디어

비선형적 컨텐츠. 중간에 link 타고 갈 수 있고, 동영상, 다른 사이트 등을 껴 넣을 수 있다. (책은 선형)


3. 분산시스템

자료의 내용이 전세계적으로 퍼져있고, 자료의 처리도 서버와 클라이언트가 분담한다.




REST


* Architecture "Style"로 반드시 지켜야 하는게 아니라, 약간의 타협을 통해 운영 가능하다.

Server / Client

Stateless

Cache

Uniform Interface ( GET, POST, PUT, DELETE 등의 8개의 Method 만 사용 )

Layered System

Code On Demand ( Java Applet, Flash, JavaScript )




URI : Uniform Resource Identifier


ex) http://user:pass@blog.examples.com:8000/search?q=test&debug=true#n10

URI Scheme : http

User : user:pass

Host name : blog.examples.com

Port number : 8000

Path : /search

Query Parameter : q=test&debug=true

URI fragment : #n10


* URI 는 % encoding.

% encoding 에서는 대문자, 소문자 구별이 없다.

%xx 의 16진수를 기반으로 인코딩한다.


* 앞으로의 상황을 고려해서라도 UTF-8 이 가장 좋은 인코딩

UTF-8 은 한 글자가 3바이트로 세상의 모든 언어 표현가능.


* 스펙상 URI 의 길이 제한은 없으나, 대부분의 브라우저가 구현상 제한이 있다.


* URN 은 Uniform Resource Name 으로 도메인명에 종속적이지 않은 주소체계.

URL 이 영구적이라는 특성 때문에 사용하지 않는다.

URL 은 자료의 위치개념이 강하고, URI 는 specific 한 객체 자체 개념이 강하다.




URI 의 설계


* 좋은 URI 는 변하지 않는다.

프로그래밍 언어에 의존적인 확장자와 경로를 포함하지 않는다.

예) cgi-bin, .pl, servlet, .do 등


메서드명과 세션 ID 를 포함하지 않는다.

예) ?action=showPage, jsessionid=12345


URI는 리소스를 표현하는 명사로 한다.

해당 리소스를 취득할지 갱신할지 등은 HTTP 메서드로 결정한다.

리소스는 그 identification 만 표현할 수 있으면 된다.


* URI 를 변경하고 싶을 때는 301 Moved Permanently 와 함께 Location Header 에 redirect 되야 할 주소를 전달해 주어 client 에서 유기적으로 redirect 되도록 해야 한다.


* URI 설계 테크닉

구현에 의존적이지 않은 확장자로 표현을 지정한다.

언어를 지정하는 확장자( .ko, .fr )를 사용하여 불필요한 Content Negotiation 을 지양한다.

참고로 Content Negotiation 은 Accept 관련 Header 를 사용하여 한다.


계층구조를 적용하기 힘든 경우 매트릭스 URI 를 사용한다.

예) http://example.com/map/lat=35.7;lng=139.7 

     http://example.com/map/35.7, 139.75


불투명(Opaque)하게 설계해야 한다.

클라이언트 쪽에서 URI 를 구성하거나, 확장자로 리소스의 내용을 추단하거나 할 수 없게 해야 한다.


* URI 를 강하게 의식하기

URI 는 리소스 이름

URI 는 수명이 길다.

URI 는 브라우저가 어드레스 란에 표시한다.




HTTP


* HTTP 버전

0.9

팀 버너스리가 웹을 처음 발명했을 때 사용하던 녀석. 헤더가 없었고, HTTP Method 는 GET 뿐.

1.0

최초 표준화된 녀석으로, 헤더가 도입되고, HTTP Method 가 추가되었다.

1.1

현재 가장 많이 쓰이는 버전으로 Accept 헤더에 의한 Content Negotiation, Cache Control, 지속적 연결 등의 기능이 추가

이후

WebDAV 등 확장 스펙들이 공개되고, WS-* 규격이 난립. 하지만 REST 아키텍쳐로 1.1을 효과적으로 활용하자는 움직임이 강함.


* Client & Sever

클라이언트에서 일어나는 일

1. 요청 메세지 구축

2. 요청 메세지 송신

3. 응답이 돌아올 때까지 대기

4. 응답 메세지 수신

5. 응답 메세지 해석

6. 클라이언트의 목적 달성을 위한 처리





서버에서 일어나는 일

1. 요청을 대기

2. 요청 메세지 수신

3. 요청 메세지 해석

4. 적절한 애플리케이션으로 처리를 위임

5. 애플리케이션 프로그램으로부터 결과를 취득

6. 응답 메세지 구축

7. 응답 메세지 송신


* 요청 메세지

GET /test?q=test#n10 HTTP/1.1

Host:example.com:8080


POST 의 경우 Header 이후에 한 라인 CRCF 후 Body 내용이 들어갈 수 있다.


* 응답 메세지

HTTP1.1 200 OK

Content-Type:application/xhtml+xml; charset=utf-8


Body...


* Stateless 의 장점과 단점

장점

서버의 구현이 단순해진다.

단점

송신할 데이터 양이 많고, 인증과정 등이 있다면 부하가 걸리는 처리가 늘어나 퍼포먼스의 저하가 초래된다.

통신 에러에 대한 대처가 어렵다.




HTTP Method ( 총 8개 )


GET

POST

PUT

DELETE

HEAD : 헤더(메타 데이터)만 취득

OPTIONS : 서포트하는 메서드의 종류 취득

TRACE : Loop back 시험

CONNECT


* POST

POST는 보통 Resource Create 에 사용된다.

나머지 Method 로 처리불가능한 것은 모두 POST 처리 가능하긴 하다.

201 Created 를 return 할 경우 Header 의 Location 에 생성된 resource URI 를 넣어준다.


* PUT

PUT은 보통 Resource Update 와 Create 에 사용된다.

Create 에 사용되는 경우는 원하는 주소를 지정해야 한다.

Update 의 경우 변환된 내용을 반환하거나, 204 No Content 를 반환하고, Create 의 경우는 201 Created 만 반환한다.


* DELETE

Resource Delete 에 사용되며, 200 OK 나 204 No Content 를 반환한다.


* HEAD

바디부분은 받지 않는데, 네트워크 대역을 절약하면서 리소스의 크기를 비롯한 부가정보를 알기 쉽고, Content Negotiation를 수행할수도 있다.


* OPTIONS

해당 Resource 가 지원하는 메서드 목록을 받는다.

이 값은 Header 의 Allow 값에 Comma Separated 되어 전달되어온다.


* Form 태그와 HTTP Method

Form 태그의 경우 GET 과 POST 만을 지원한다.

하지만, HTTP Method 는 그 나름의 의미가 있기 때문에 Ruby 스타일의 _method 를 사용할 수 있다.

<form target="/item" action="POST">

<input type="hidden" id="_method" value="PUT"/>

...

</form>


또 다른 방법으로 X-HTTP-Method-Override 라는 방법이 있는데, 이는 POST 가 application/x-www-form-urlencoded 를 사용하여 일부 내용 전달에 어려움이 있을 때 사용된다.

이는 헤더에 내용을 전달하면 된다.


* 조건부 요청

If-Modified-Since 헤더를 이용하여, 내용이 변했을 때 GET 으로 내용을 추가 가져온다.


* 멱등성과 안정성

멱등성은 몇번을 수행해도 결과가 동일한 것을 말한다.

안정성은 리소스의 상태를 변경시키지 않는 것을 말한다.

GET, HEAD 는 멱등이고 안전.

PUT, DELETE 는 멱등이지만 안전하지 않다.

POST 는 멱등이지도 안전하지도 않다.

위의 설명은 원칙적으로 그렇지만, 메서드의 구현을 잘못 했을 경우 지켜지지 않을 수도 있다.







Status Code( 스테이터스 코드 )


* 스테이터스 코드의 분류와 의미

1xx : 처리중

처리가 계속되고 있음을 나타낸다. 클라이언트는 요청을 계속하던지 서버의 지시에 따라 업데이트하여 재전송한다.

2xx : 성공

3xx : 리다이렉트

다른 리소스로의 리다이렉트를 나타낸다. 보통 이 스테이터스 코드는 Location 헤더를 동반하고, 해당 주소로 리다이렉트한다.

4xx : 클라이언트 에러

클라이언트 요청에 에러가 있다. 에러를 해결하지 않으면 몇번을 요청해도 정상적인 결과를 얻을 수 없다.

5xx : 서버 에러

서버에 에러가 있다. 서버 측 원인이 해결되면, 동일한 요청에 정상적 결과를 얻을 수 있다.


코드의 첫글자를 통해 최소한의 처리가 가능하다.


* 자주 사용되는 스테이터스 코드

200 OK

201 Created

POST 의 경우 Location 헤더를 함께 return 한다.

301 Moved Permanently

Location 헤더를 함께 전달하여 리다이렉트를 가능하게 한다.

303 See Other

보통 POST 로 조작한 리소스를 GET 으로 가져올 때 사용

400 Bad Request

적절한 클라이언트 에러를 나타내는 코드가 없거나, 일반적인 클라이언트 에러를 나타낸다.

401 Unauthorized

인증이 실패하거나, 권한이 없는 리소스 접근할 때 발생한다. WWW-Authenticate 헤더를 통해 인증방식을 전달한다.

404 Not Found

리소스를 찾을 수 없을 때 발생

500 Internal Server Error

일반적인 서버 에러나 적절한 서버에러코드가 없을 때 사용된다.

503 Service Unavailable

서비스가 점검 등의 이유로 일시적으로 정지되었을 때 사용되며, Retry-After 헤더를 사용하여 다음 접속 시간을 권유한다.


* 각 프로그램이나 서버의 종류에 따라 스테이터스 코드를 조금씩 다르게 사용하는 경향이 있으니 주의한다.




HTTP Header ( HTTP 헤더 )


* HTTP 기본 헤더

Content-Type

미디어 타입을 지정한다.

예) application/xhtml+xml : / 왼편은 타입이고, 오른쪽은 서브타입이다.

charset 도 함께 정의하는데, 보통 UTF-8 을 사용한다.


Content-Language

예) ko-KR : - 왼편에 ISO 639 지정 언어코드가 들어가고, 오른편에는 ISO 3166 이 정의한 지역코드가 들어간다.


* Content Negotiation

Accept

예) Accept: text/html, application/xhtml+xml, application/xml; q=0.9, */*;q=0.8

q value 는 소수점 이하 세자리 이내의 0~1 사이의 수치가 들어간다.

text/html, application/xhtml+xml 의 경우 default인 1,

application/xml 은 0.9,

나머지는 0.8 의 우선순위를 가진다.


만약 클라이언트의 Aceept 헤더에 지정한 미디어 타입이 서버가 대응하는 내용이 아니면 406 Not Acceptable 을 반환한다.


Accept-Charset

예) Accept-Charset : EUC-KR,utf-8;q=0.7, */*;q=0.7


Accept-Language

예) Accept-Language: ko, en-us;q=0.7, en;q=0.3


* 기타 헤더

Content-Length

바디의 길이를 지정한다.


Transfer-Encoding:chunked

바디를 분할하여 전송한다.


* 인증 헤더

인증이 필요한 리소스를 권한 없이 접근하는 경우 401 Unauthorized 스테이터스 코드와 함께 WWW-Authenticate 헤더가 함께 리턴된다. WWW-Authenticate 에는 서버의 인증정보를 담고 있다.

예) WWW-Authenticate:Basic realm="example.com"


베이직 인증

유저 이름과 패스워드에 의한 인증방싣이다.

Authorization 헤더에 넣어 요청마다 전송해야 한다.

예) Authorization: Basc dXNlcjpwYXNzd29yZA==

Basic 인증 방식은 유저이름과 패스워드를 : 로 연결하고 Base64 로 인코딩한 문자열인데, Base64 방식은 디코딩이 간단히 된다. 따라서 Basic 인증을 사용할 경우에는 SSL, TLS 를 이용해 HTTPS 통신을 하고, 통신선로 상에서 암호화하는 것을 검토해야 한다. 이게 어렵다면 다른 인증방식을 사용해야 한다.


Digest 인증

Basic 인증보다 보안이 강화된 인증 방식이다.

메세지 다이제스트의 줄임말로 이는 어떤 메세지에 대해 해시 함수를 적용한 해시값을 말한다.

예) WWW-Authenticate: DIgest realm="example.com", nonce="1ac421d9e0a4k7q982z966p..", qop="auth", opaque="92eb5ffee5ae.."

WWW-Authenticate 의 값을 Challenge 라고 부르는데, 이 값을 이용하여 요청할 때 다시 authenticate 해서 보내야 한다.

nonce 는 number used once 의 약자로 한번만 사용되는 숫자이다. 모든 요청에 대해 매번 변한다. 이는 서버구현에 의존하는데 기본적으로 타임스탬프와 서버 고유의 어떤 값을 이용해 생성한다.

qop 는 quality of protection 의 줄임말로, auth 나 auth-init 값이 들어간다. auth의 경우 메서드와 URI로부터 다이제스트를 작성하고, auth-init 의 경우 메서드와 URI, 그리고 메세지 바디를 이용해 digest 를 작성한다. auth-init 의 경우는 메세지 전체의 보안도 보증된다.

opaque 는 클라이언트에서 추측할 수 없는 문자열이다.





(1)값 : 유저이름, realm, 패스워드는 : 로 연결하고 MD5 해시 값을 구한다.

(2)값 :메서드와 URI 패스를 : 로 연결하고 MD5 해시 값을 구한다.

(1)의 값, nonce, 클라이언트가 nonce를 보낸 횟수, cnonce, qop값, 2의 값을 : 로 연결하고 MD5 해시 값을 구한다.

이 값을 response 필드에 넣고 다시 송신해야 한다.

ex) Authorization:Digest username="user", realm="example.com", nonce="1ac421d9e...", uri="/test", qop="auth", nc=00000001, cnonce="900150983cd24fb...", response="0fde218e...", opaque="92eb5ffee5ae2..."


Digest 인증의 장점과 단점

서버에 패스워드의 해시값만 보관하면 되므로 보안 위험이 줄어든다.

Basic 인증의 경우 같은 URI 공간의 리소스라면 클라이언트는 한번 인증되면 계속 user:password 만 보내면 다시 리소스에 접근할 수 있지만, Digest 의 경우 서버로부터 nonce 를 부조건 다시 받아 계산해야 한다. 따라서 무조건 어떤 리소스든 401 Unauthorize 응답을 한번은 얻어야 한다. 그래서 Digest 인증의 경우 무거워서 보급이 잘 안 되어, 여러 서버에서 옵션으로 사용하곤 한다. https 를 대신 운영하는 곳이 많다.


WSSE 라는 표준 이외의 인증방식도 있다.


요즘은 통합 인증관리, 권한위임 등을 위한 OpenID 와 OAuth 등이 유행하고 있다.


* 캐시 해더

Pragma:no-cache

리소스를 캐시하지 말것을 말한다.


Expires

캐시의 유효기한을 나타낸다.


Cache-Control

상세한 캐시 방법을 지정한다.

예) Cache-Control:max-age:86400

86400 초 동안 캐시가 유효하다.


* 조건부 GET

If-Modified-Since 를 통해 해당 내용이 바뀌었다면 GET 해서 가져올 수 있다.

바뀌지 않았을 경우 304 Not Modified 와 Last-Modified 값이 return 된다.


If-Modified-Since 와 Last-Modified 헤더에 의존한 조건부 GET 은 편리하지만, 시계 표준차이문제나 시계기능 사용이 어려운 서버 등에서 사용하기가 어렵다. 이 때는 If-None-Match 와 ETag( 엔티티 태그) 헤더를 사용한다. ETag 는 어떤 조건에 의해 해당 파일의 변경여부를 문자열로 나타낸 값이다.


* 지속적 접속

HTTP 1.0에서는 응답이 올때마다 TCP 커넥션을 끊었지만, HTTP 1.1 에서는 접속상태를 유지한다.

Connection 헤더에 close 값을 전달했을 때 끊는 방식을 사용한다.

HTTP 1.0에서는 지속적 연결을 위해서 Keep-Alive 헤더를 사용했다.




Microformats 와 RDF(Resource Description Framework)


* 시멘틱 웹을 위한 xml format.


* RDF 는 주어, 술어, 목적어를 이용해 웹의 리소스에 메타 데이터를 부여한다. 복잡하고, 통일성이 없고, 별도의 메타데이터 파일이나 구문에 기록이 필요하다.


* microformats 의 경우는 rel 속성을 이용하여 리소스에 메타 데이터를 부여하며, HTML 태그 안에 삽입 가능하다.


* microformats 에서 가장 많이 쓰이는 것들은 rel-license 와 rel-nofollow 이다.


* microformats 는 간단하지만, class 와 rel 속성에 값을 부여하기 때문에, 이름이 중복될 가능성이 있다.


* RDFa 는 RDF in Attribute 의 약자로 외형은 microformat 과 거의 동일하나, microformats 가 가진 이름충돌 문제를 xml의 이름공간으로 해결하는 방식이다.




ATOM


* RSS 스펙의 난립에 대응하여 확장성 있는 피드 표준 포맷을 책정한 것.


* RSS 는 주로 블로그의 신착정보를 전달하는 피드 목적으로 이용되지만, Atom 은 블로그 뿐 아니라 검색엔진이나 사진관리 등 다양한 웹 서비스의 웹 API 로 이용될 수 있다.




JSON을 이용한 크로스 도메인 통신


* JSONP

JSON with Padding 의 약자이다.

Ajax에서 이용하는 XMLHttpRequest 라는 JS 모듈은 보안상의 제한으로 인해, JS 파일을 가져왔던 동일 서버하고만 통신할 수 있다. JS 가 다른 서버와 통신할 수 있다면, 브라우저에서 입력한 정보를 부정하게 다른 서버에 전송할 수 있기 때문. 크로스 도메인 통신이란 이와는 반대되는, 불특정 다수의 도메인 서버에 접속하는 것을 말한다.

이 문제는 <script> 태그로 해결할 수 있는데, <script src="..."> 를 통해 여러 사이트의 JS 파일을 읽을 수 있다. 이는 보안제한에 해당하지 않는 문제이다. 이 성질을 이용해 callback 함수를 전달하여 다른 서버의 JS 를 통해 데이터를 받아올 수 있는데 이를 JSONP 라고 부른다.

예) <script src="http://example.com/data.json?callback=foo">




웹 서비스의 설계


* 읽기전용 웹 서비스의 설계 ( 리소스 지향 아키텍처 접근방법 )

1. 웹 서비스에서 제공할 데이터를 특정

2. 데이터를 리소스로 나눈다

3. 리소스에 URI 로 이름을 부여한다.

4. 클라이언트에 제공할 리소스의 표현을 설계한다. ( xml, json, xhtml 등 )

5. 링크와 폼을 이용해 리소스와 리소스를 연결한다.

6. 이벤트의 표준적인 코스를 검토한다.

7. 에러에 대해 검토한다. ( 존재하지 않는 URI 지정, 필수 파라미터 미지정, 지원하지 않는 메서드 사용 등 )


* 쓰기 가능한 웹 서비스의 설계

쓰기 가능한 웹 서비스는 트랜잭션, 일괄처리, 베타제어를 고려해야 해서 어렵다.

일괄처리의 경우 일부만 성공한 경우는 207 Multi-Status 와 함께 WebDAV 의 <D:multistatus>요소를 조합하는 방법과 200 OK 와 독자 포맷을 조합하는 방법으로 성공과 실패여부를 전송한다.

트랜잭션은 여러개의 처리를 Atomic 하게 처리해야 한다. 임시 Resource 에 여러차례 시도해서 모두 성공하면, 서버에 Transaction 을 하라는 명령을 내리는 방법과 서버에서 알아서 Transaction 을 구현하는 두 가지 방법이 있다.

DELETE 의 경우에 상위 리소스를 삭제했을 때, 하위리소스도 삭제할지 불가능하게 할지도 정해야 한다.

배타제어는 Mutual Exclusion 이라고 해서 Lock 을 거는 것과 같다. 이 잠금에는 비관적 잠금(Pessimistic Lock)과 낙관적 잠금(Optimistic Lock)이 있다.


Pessimistic Lock 은 경쟁상황이 아예 일어나지 않도록 하는 Lock이다.

잠금을 구현하는 방법은 WebDAV 의 LOCK/UNLOCK 을 이용하는 방법이 있다. HTTP Method로 LOCK 을 사용하는데, 이 방법으로 잠긴 리소스에 다른 user가 접속하면 423 LOCKED 가 return 된다. 잠금을 제대로 지정한 후 If 헤더로 Locktoken 을 지정하여야 해당 락을 제대로 사용할 수 있다. 잠금해제는 UNLOCK Method 를 이용해서 하며, 이 때 Lock-Token header 를 함께 전달한다. 

서버에서 Lock 을 구현하는 방법도 있는데, scope, timeout 과 같은 parameter 를 이용하는 것이 보통이다.

비관적 잠금은 시스템의 스케일이 커질수록 문제가 커진다.


Optimistic Lock 은 여러 사람이 항상 같은 리소스를 계속 편집하는 경우가 거의 없다는 전제하에 경쟁이 일어났을 때 합리적으로 대처하는 방식이다.

낙관적 잠금은 조건부 편집을 사용한다. 서버에서 전달되는 ETag 나 LastModified 값과 클라이언트에서 전달하는 If-Match Header 값을 이용하여 구현한다. If-Match 헤더를 통해 전달된 값이 valid 하지 않을 때는 412 Precondition Failed 를 return 한다. 이 때는 여러가지 처리방법이 있는데, 서버에서 리소스를 따로 저장했다가 merge 하는 방법, 클라이언트에서 reload 후 재시도 등의 방법이 대표적이다.


* 웹 서비스에서 제공하는 데이터를 특정하고 리소스로 나누는 방법.

관계 모델 ER 다이어그램 이용

중심이 되는 table 에서 정보를 추출

탑 레벨 리소스와 URI 계층구조 등을 설정하기가 어렵다.

객체 지향 모델의 클래스 다이어그램 이용

is-a, has-a 를 이용하면 탑 레벨 리소스와 URI 계층구조를 구하기 쉽다.

정보 아키텍처 이용

지식이나 데이터의 조직화를 통해 정보를 알기 쉽게 전달하는 표현기술.



반응형

댓글