# 서울숲_J_Day16 리뷰 레포트 ### 참석자 - 김재현, 이상원, 이주형, 신철헌 ## 1. 코드 동작 이해 오늘 구현한 코드는 url, response, request 3개의 객체로 작동한다. - url 객체 - url은 많은 정보를 담고 있다. 우리는 url에서 해당정보들을 분리해야 한다. - 먼저 분리를 위한 정규표현식을 작성한다. 우리가 오늘 구현한 코드에서 사용한 정규표현식은 다음고 같다 ```javascript const urlPattern = RegExp("^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?"); ``` - 파싱된 결과에서 각각의 정보값을 정확하게 추출하기위해 String 함수들로 가공한다. - 우리는 host, lastPathComponent, PathComponents, port, query, scheme, isFileUrl, userInfo, absoluteString 정보를 추출했다. - 이 중 호스트랑 스키마는 꼭 포함되어야하는 정보이며 포함이 안될 시 에러를 발생한다. - 또한 url을 비교하는 함수를 포함한다. 이 함수는 비교 상태에 따라 5가지 상태를 결과값으로 출력한다. - response 객체 - response 객체는 request 요청으로 받은 응답을 매개변수로 받는다. - 헤더와 바디는 개행문자 2개로 구분지어져 있기 때문에 '\r\n\r\n'으로 split 함수를 이용하면 분리된다. - http요청이 성공적으로 완료되었는지를 알려주는 status code는 헤더의 첫 번째 줄에 포함되어 있다. 공백을 기준으로 나누면 앞에는 http의 버전, 뒤에는 status code가 위치한다. - response line은 헤더의 첫 번째 줄을 의미한다. 헤더의 첫 번째 줄의 내용을 할당한다. - content length는 헤더에 명시되어있다. 헤더의 내용을 적절하게 파싱하여 할당한다. content length는 바디의 길이를 의미한다. 실제 바디의 길이와 비교하기 위해서는 소켓과 버퍼의 인코딩값을 지정해주어야 정확하게 비교할 수 있다. - request 객체 - 기존에 만들어 둔 URL객체를 매개변수로 사용하는 객체이다. - 받은 URL의 호스트 부분을 node 모듈인 DNS를 사용하여 도메인 주소를 이용하여 IP 주소를 알아낸다. - 후에 NET 모듈을 사용하여 소캣을 생성한다. - 적절한 HEADER를 만들어 write 해준다. - 한번에 모든 데이터가 들어오는 것이 아니기 때문에 data를 받아 올 수 있는 전역변수를 만들어 계속 추가해준다. - 소캣이 닫히면 (`client.on('close', function())`) Response 객체를 생성하여 받아온 데이터를 넘겨주고 적절하게 Header와 Body를 나누어준다. - Body 부분은 fs모듈을 사용하여 html파일로 만들어준다. ```javascript stringify() { let header = 'GET / HTTP/1.1\r\n'; header += 'Accept: text/html\r\n'; header += 'Host:' + `${this.url.host}\r\n`; header += 'Keep-Alive: timeout=15\r\n'; header += 'User-Agent: Mozilla/5.0\r\n\r\n'; return header; } ``` ```javscript requestData() { var total_data; const host = this.url.host; this.url.findDNS(host).then((ip) => { var client = net.connect({port:80, host:ip}, ()=>{ console.log(`${v} 80`); client.setTimeout(500); client.setEncoding('utf8'); client.write(this.stringify()); }) client.on('data', function(data) { total_data += data.toString(); }) client.on('end', function() { console.log('client disconnected'); }) client.on('close', function() { this.response = new httpResponse(total_data); const splitdata = this.response.splitHeaderBody(); const body = splitdata[1]; const asd = this.response.analysisHeader(); const header_Content_length = parseInt(asd[4].split(":")[1].trim()); console.log(`header_content_length: ${header_Content_length} , body_length = ${body.length}`); console.log(asd); fs.writeFile('./body.html', JSON.stringify(body), ()=> {}); // console.log(body); }) }); } ``` ## 2. 코드 동작 개선 #### 김재현 - url에 꼭 포함되어야하는 정보를 구별하지 못했다. http 문법을 더 공부해서 어떤 정보는 꼭 포함되어야하는지 반영해야 겠다. - response 객체에서 body를 다룰 때 버퍼를 사용하긴 했지만 잘 활용하지는 못한 것 같다. 버퍼 객체에 대해서 조금 더 공부해봐야 겠다. - 정규표현식으로 어떻게 url을 가공하느냐에 따라 이후 조건문들이 많이 바뀌는 것 같다. 어떤 정규표현식이 제일 적절할지 고민하고 결정해야한다. - http 프로토콜에 대해서 학습하고 이해 할수 있는 시간이었다. 네트워크가 어떻게 요청과 응답을 주고받는지 이해함으로써 네트워크 통신에 대한 이해도가 높아졌다. #### 이상원 - 인터넷 주소를 입력하고 나서 어떻게 브라우저가 그 페이지를 가져올 수 있는지를 이해해보자. - url객체에서 같은 url인지 판단하는 부분을 자의적으로 해석한 부분이 많은데 조금 더 정확히 정보를 찾아서 반영하자. - 와이어샤크 사용법에 조금 더 익숙해지자. - httpRequest에서 요청을 다 받을 때까지 기다리게끔 코드를 구성하자. - 정규식의 사용방법에 조금더 익숙해져야겠다. #### 이주형 - URL 객체를 만들 때 정규방정식을 사용했으면 더욱 깔끔한 코드가 되었을 것 같다. - 예외 처리에 대해서 RFC를 보며 파악했지만 좀 더 자세하게 예외 처리를 했으면 좋았을 것이다. - 시간이 없어 Request와 Response 역할의 경계가 모호했던 것 같다. 더 모듈화를 통해 분명하게 나누면 좋을 것이다. - 인코딩 문제로 `close`를 사용해서 소캣이 닫힌 뒤에 받은 데이터를 사용했음에도 불구하고 길이가 다르게 되었다. 받을 때만 인코딩을 설정해 주는 것이 아니라, 소캣을 생성할 때도 인코딩을 해줘야 한다. #### 신철헌 - http 프로토콜에서 통신을 주고받는 방식을 좀 더 이해하고 작성할 필요가 있다. ( contente length 문제 개선 필요) - readonly property 를 작성하기 위해서 숨겨진 프로퍼티가 필요하다. ## 3. Consideration #### 스스로 확인할 사항 ##### URL 구성 요소에 대해 학습한다. ``` http://music.naver.com/listen/top100.nhn?domain=OVERSEA&duration=1h#content 프로토콜| 도메인 |파일 디렉토리 경로|쿼리, 파라미터 | 플래그먼트 와 파일명 ``` - 프로토콜 : 컴퓨터 간 정보를 주고 받을 때 통신 방법에 대한 규칙을 표기한다.보통 일반적인 url에서 많이 쓰이는 대표적인 프로토콜은, http와 https 등이 있다. - 도메인 : 네트워크상의 컴퓨터 주소를 의미한다. 도메인 전체에는 국가나 기관의 정보, 그리고 도메인이름과 도메인에 속한 호스트 정보가 기입된다. 각 정보는 점(.)으로 구분할 수 있으며, 뒤에서부터 순차적으로 확인할 수 있다. music.naver.com/listen/top100.nhn에서, 도메인은 'music.naver.com'이며, 도메인은 상위도메인, 도메인이름, 호스트명으로 이루어져 있다. - 상위도메인명은 'com'으로 볼 수 있다. - 도메인명은 'naver'로 볼 수 있다. 인터넷상의 컴퓨터 주소는 숫자로 이루어진 IP 주소로 표현되며, 이 숫자로 이루어진 주소를 알기 쉬운 영문으로 표현한 것이 도메인명이다. - 호스트명은 'music'으로 볼 수 있다.호스트의 사전적 의미는, 인터넷에 연결된 지역(컴퓨터)의 이름이며 좀 더 쉽게는 도메인에 속한 컴퓨터 이름, 도메인의 하위 개념으로 이해할 수 있다. 예를 들어 news.naver.com 라는 url에서 도메인이름은 'naver.com'이 되며, 호스트명은 naver.com라는 도메인에 속한 'news'가 된다. 호스트명은 m.news.naver.com에 붙은 'm.news'와 같이 2개 이상 사용할 수도 있으며, m.news.naver.com은 new.naver.com 하위에 속한 추가 호스트주소를 갖고 있는 다른 url로 해석할 수 있다. - 파라미터 (Parameter, Query String) - 가변적인 콘텐츠를 처리하기 위한 정보. - 파라미터는 쿼리 스트링이라고도 하며, 정보에 따라서 페이지의 콘텐츠가 가변적일 수 있을 때 많이 사용한다. - 검색 결과 페이지로 예를 들면, 페이지는 하나이지만 검색어에 따라 다른 콘텐츠나 레이아웃으로 구성된다. 페이지 url에서 검색어와 같은 정보를 구분할 수 있도록 url 뒤에 파라미터라는 매개 변수를 추가하여 검색어 정보를 url에 함께 전달한다. 파라미터는 url 의 파일명 뒤 물음표 이후에 나열이 되며, 이름과 값으로 구성된 세트가 1개 이상 존재할 수 있다. 이 세트는 엔드(&) 기호로 구분된다. - URL을 구분하기 위한 정보 - 한 페이지의 가변적인 콘텐츠를 구분 하긴 위한 정보 외에도, 한 페이지 url를 상황에 따라 구분하기 위한 용도의 추가 정보로 파라미터를 사용할 수도 있다. - 한 페이지로 이동하는 url을 여러 매체를 통해 홍보를 하고, 추후에 url에 유입된 사용자가 홍보를 통해 들어온 사용자인지, 홍보를 통해 들어온 사용자라면 어떤 매체를 통해 들어왔는지 확인해야 하는 상황을 예를 들자. url의 유입 경로를 통해 이전 페이지의 주소는 알 수 있겠지만, 홍보를 통해 들어온 url이라는 정보는 100% 정확하지 않다. 네이버 검색 결과의 광고 서비스로 예를 들자면, 이전 페이지가 같은 검색 결과 페이지일지라도 홍보를 진행한 상단의 파워링크 영역에서 유입 된 사용자와 하단의 일반 검색 결과에서 유입 된 사용자를 단순히 이전 url만으로는 구분할 수 없다. 따라서 이와 같은 구분이 필요한 상황에서 url을 배포할 때 정보를 구분할 수 있는 파라미터값을 각각 추가하고(ex: 파워링크 영역의 링크에는 '...?t=pl'와 같은 파라미터를 추가) 나중에 url에 접근되는 사용자의 파라미터 값을 분석한다면 홍보자가 의도한 바에 맞춰 세밀한 기준으로 사용자를 구분할 수 있을 것이다. - 파일 디렉토리 및 파일명 역할을 하기 위한 정보 - 파라미터는 동일한 페이지의 일부 정보를 구분하기 위한 용도 외에도, 파일디렉토리 및 파일이름과 유사한 역할로도 쓰이는 경우가 있을 수 있다. - 플래그먼트(Fragment, Hashtag, Anchor) - 플래그먼트로 페이지의 특정 요소를 지시할 수 있다. 콘텐츠를 이루는 요소 html 태그는 id라는 고유한 속성값을 가질 수 있다. url 뒤에 해시태그를 붙인 요소의 id를 붙여서 확인하면, 해당 url 페이지에서 해시태그로 지시한 id 요소를 스크롤 이동 없이 확인할 수 있다. 이러한 기능은, 여러 콘텐츠가 나열 된 페이지의 특정 위치 정보를 사용자에게 함께 전달하고자 할 때 유용하게 쓰일 수 있다. - http://music.naver.com/listen/top100.nhndomain=OVERSEA&duration=1h#content 는, 해당 페이지에서 content 영역을 지시하는 페이지이다. [출처](https://blog.naver.com/beusable/220864070146) https://blog.naver.com/beusable/220864070146 [출처](https://m.blog.naver.com/PostView.nhn?blogId=beusable&logNo=220864664334&proxyReferer=https%3A%2F%2Fwww.google.com%2F)https://m.blog.naver.com/PostView.nhn?blogId=beusable&logNo=220864664334&proxyReferer=https%3A%2F%2Fwww.google.com%2F ##### 다양한 URL 케이스를 어떻게 처리하는지 확인한 방법을 정리한다. - 기본 URL과 상대 URL (슬래쉬로 시작하지 않음)이 주어지면 전체 URL은 다음과 같이 파생된다. - 기본 URL이 슬래시로 끝나면 전체 URL은 기본 URL에 상대 URL을 추가하여 파생된다. 예를 들어, 기본 URL이 `http://nosite.com/dir1/dir2/` 이고 상대 URL이 gee.html 인 경우 파생 URL은 `http://nosite.com/dir1/dir2/gee.html` 이다. - 기본 URL이 슬래시로 끝나지 않으면 마지막 부분이 리소스로 간주되므로 기본 URL의 부모에 상대 URL을 추가하여 전체 URL을 파생시킨다. 예를 들어, 기본 URL이 `http://nosite.com/dir1/dir2` 이고 상대 URL이 gee.html 인 경우 파생 URL은 `http://nosite.com/dir1/gee.html`이다. - 해시뱅(#!) - URL의 # 기능인 앵커를 이용한 URL이다. 현재 페이지에서 #뒤에 있는 태그를 찾아서 이동한다. - 사용자가 브라우저에 `http://twitter.com/#!/outsideris` 를 입력합니다. - 브라우저가 #뒤에 부분인 !/outsideris를 로컬에 저장하고 `http://twitter.com/`를 서버에 보냅니다. - `http://twitter.com`가 가리키는 트위터서버로 이동이 됩니다. - 서버는 루트페이지의 HTML을 대량의 자바스크립트 링크와 함께 클라이언트에게 리턴합니다. - 브라우저가 자바스크립트를 실행시키고 /outsideris를 파싱해서 oustideris에 대한 데이터를 서버에 요청합니다. - 서버에서 받은 데이터를 화면에 적절하게 뿌려집니다. - 사용 이유 - 단일 페이지 웹애플리케이션을 만들기 위해서인데, 페이지가 갱신되지 않는 것이 중요한 상황에서 현재 기술로는 페이지 갱신없이 URL을 변경할 수 있는 방법이 없다. - 그렇기 때문에 페이지 갱신없이 URL이 변경되는 것처럼 보이도록 하기 위해서 해시뱅을 사용한다. 출처: https://blog.outsider.ne.kr/698 ##### HTTP Request 종류와 HTTP Response 종류에 대해 학습하고 정리한다. 1. http request 종류 ##### 메소드로 구분한 종류 1. GET, 2. POST, 3. PUT, 4. DELETE ##### 콘텐트 타입으로 구분한 종류 3. form 형태 : URLEncoded 방식 - application/x-www-form-urlencoded - 메세지 바디 : 쿼리 문자열 4. json 형태 - application/json 5. 멀티파트 형태 : 이진파일 넘길 때 사용, 하나의 메세지 바디에 파트를 나눠서 작성 - boundary는 파트 구분자 - multipart/form-data: boundary=frontier 2. http response 종류 ##### 상태코드로 구분한 종류 1. 1xx : 정보 2. 2xx : 성공 - 200 : OK. 요청 성공 - 201 : Created. 생성 요청 성공 - 202 : Accepted. 요청 수락(처리 보장X) - 204 : 성공했으나 돌려줄게 없음 3. 3xx : 리다이렉션 - 300 : Multiple choices. 여러 리소스에 대한 요청 결과 목록 - 301,302,303 : Redirect. 리소스 위치가 변경된 상태 - 304 : Not Modified. 리소스가 수정되지 않았음 4. 4xx : 클라이언트 오류 - 400 : Bad Request. 요청 오류 - 401 : Unauthorized. 권한없음 - 403 : Forbidden. 요청 거부 - 404 : Not Found. 리소스가 없는 상태 5. 5xx : 서버 오류 - 500 : Internal Server Error. 서버가 요청을 처리 못함 - 501 : Not Implemented. 서버가 지원하지 않는 요청 - 503 : Service Unavailable. 과부하 등으로 당장 서비스가 불가능한 상태 ##### 콘텐트 타입으로 구분한 종류 1. 텍스트 text/plain, text/html 2. 코드 application/xml, application/json 3. 이미지 파일 image/png, image/jpg 4. 오디오 파일audio/mp3, video/mp4 [출처 : 블로그 - HTTP 구조 (https, request, response, 주요 상태코드)](https://sjh836.tistory.com/81) #### 다같이 확인할 사항 ##### 웹 브라우저가 동작하는 과정을 개발자 화면에서 확인하고 학습한다. - 웹 브라우저가 동작하는 과정 - 브라우저는 DNS 서버로 가서 웹사이트가 있는 서버의 진짜 주소를 찾습니다 (여러분이 상점의 주소를 찾습니다). - 그 다음 브라우저는 서버에게 웹사이트의 사본을 클라이언트에게 보내달라는 HTTP 요청 메세지를 서버로 전송합니다. (상점으로 가서 상품을 주문합니다.) 이 메세지, 그리고 클라이언트와 서버 사이에 전송된 모든 데이터는 TCP/IP 연결을 통해서 전송됩니다. - 이 메세지를 받은 서버는 클라이언트의 요청을 승인하고, "200 OK" 메세지를 클라이언트에게 전송합니다. "200 OK"는 "물론이죠. 당신은 웹 사이트를 볼 수 있어요! 여기 있어요" 라는 의미입니다. 그 다음 서버는 웹사이트의 파일들을 데이터 패킷이라 불리는 작은 일련의 덩어리들로 브라우저에 전송하기 시작합니다. - (상점은 여러분이 주문한 상품을 전달하고, 여러분은 그것을 집으로 가져갑니다.) - 브라우저는 이 작은 덩어리들을 완전한 웹 사이트로 조립하고, 당신에게 보여줍니다. (상품이 당신의 문에 도착합니다. — 새 것이죠, 멋져요!) [출처: MDN Web DOC - 웹의 동작 방식](https://developer.mozilla.org/ko/docs/Learn/Getting_started_with_the_web/%EC%9B%B9%EC%9D%98_%EB%8F%99%EC%9E%91_%EB%B0%A9%EC%8B%9D) ##### 리눅스/유닉스 환경에서 wget 이나 curl 명령 사용방식에 대해 학습한다. - wget - wget이란 인터넷의 파일을 다운로드받는 리눅스 명령어 중의 하나이다. - 윈도우의 유명한 다운로드 전문 프로그램인 플래시겟과 비슷하지만, 다만 그래픽 환경이 없고 텍스트 모드입니다. - 사용 방법 - wget [옵션] [다운로드하고자 하는 URL] - [옵션] - -r 디렉토리 구조와 파일을 그대로 하여 복사 - -b 백그라운드에서 파일 다운로드 실행 - -c 연결이 끊긴 시점부터 이어서 파일 다운로드 - 예시: 네이버 메인 페이지 다운로드 받기 - `wget http://www.naver.com/index.html` - curl - 서버와 통신할 수 있는 커맨드 명령어 툴이다. - 웹개발에 매우 많이 사용되고 있는 무료 오픈소스이며, curl의 특징으로는 다음과 같은 수 많은 프로토콜을 지원한다는 장점이 있습니다. - DICT, FILE, FTP, FTPS, Gopher, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, POP3, POP3S, RTMP, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, Telnet, TFTP - 사용 방법 - Header 설정하기 - `curl -H "Content-Type: application/json"` (application/json 으로 content type 설정) - `curl -H "Content-Length: 10000" `(content length 10000으로 설정) - POST 메소드 사용 (POST가 디폴트이기 때문에 -X를 쓸 필요가 없다.) - `curl http://naver.com -d test=ok -d test2=ok` (-d : 함께 전달할 파라미터값 설정하기) - Delete 메소드 사용 - `curl -X "DELETE" http://webisfree.com/action/` (-X : 사용할 방식 메소드 선택하기 ) 출처: https://webisfree.com/2017-05-25/curl%EC%9D%84-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0 ##### 브라우저가 처리하는 과정을 WireShark 같은 네트워크 패킷 분석 도구를 통해서 확인한다. ![](https://i.imgur.com/ecVcnOr.jpg) - `zum.com` 홈페이지에 대한 접속을 와이어샤크로 사용한 것이다. - HTTP는 포트번호 80번을 사용하기 때문에 http 접속을 위해 개인 포트번호에서 80번으로 요청을 보내고 그에 대한 응답을 받는 것을 볼 수 있다. ##### WireShark 도구가 동작하는 원리에 대해 학습한다. - wireshark는 패킷 스니핑으로 패킷을 캡쳐한다. 1. 수집 : 회선에서 원본 바이너리 데이터를 수집, 일반적으로 패킷 수집 시 네트워크 인터페이스를 무차별 모드로 변경. 이 모드에서 네트워크 카드는 특정 네트워크를 주소 지정하는 트래픽 뿐 만 아니라 특정 네트워크 영역 내의 모든 네트워크 트래픽을 엿볼 수 있음. 2. 변환 : 수집된 바이너리 데이터를 읽을 수 있는 형태로 변환. 대부분이 커맨드 라인으로 동작하는 패킷 스니퍼 프로그램은 변환 단계까지 수행. 3. 분석 : 수집된 데이터와 변환된 데이터에 대한 실제적인 분석이 이루어지는 단계로 패킷 스니퍼는 스니퍼 프로그램 내부에 존재하는 정보를 이용해 수집된 네트워크 데이터의 프로토콜을 검증하고 특징과 내용을 분석 출처: https://minaninyos.tistory.com/entry/와이어샤크-패킷-분석-및-네트워크-기초 [minaninyo's]