6월 4주차 새로운 지식- content-type, 사이드 랜더링, Custom Exception, ResponseEntity, PWA, Passkeys

Daniel_Yang·2022년 6월 20일
0

웹 개발의 정석인 mozilla를 참고하자!

6월 20일

Content-type

(MIME type, Media type와 비슷하다고 할 수 있다)


참고 reference
content-type header 영상
Content-type -HTTP 링크
content-type이 쓰이게 된 이유: 텍스트 파일 변환(binary 파일) 링크
content type 링크


  • 주제 선정 이유: Postman을 계속 사용하면서 header 부분이 궁금해졌다.

MIME type은 파일의 형식을 나타내는 문자열로 파일과 같이 송신되는데 content의 형식을 나타내기 위해 사용한다. 예를 들면 오디오 파일은 audio/ogg로 그림 파일은 image/png로 분류할 수 있다.

  • http 프로토콜로 데이터를 보낼 떄 서버가 이해할 수 있는 것. 이를 모르면 전달하는 데이터 형식이 변할 떄 왜 오류가 발생했는지 모른다.

  • 목적: 이에 대한 이해가 있으면 서버와 커뮤니케이션하는 데이터에 대해 빠르게 맞추고 해결한다.

  • 웹브라우저에서는 HTTP 통신으로 데이터를 수신받을 때, 어떠한 데이터가 올 지 모르기 떄문에 웹브라우저가 서버로부터 수신받을 떄, content-type header에 무엇을 기대할지 알려준다. 데이터를 어떻게 처리(분석, 파싱, 처리)해야 할 지 판단.
    - 예를 들어, 웹 페이지 수신받을 때 HTML인지 CSS, JS인지 모른다.

  • 수신받을 때, content-type과 파일 확장자(file extension)의 결합으로 합리적으로 추츤한다.
    - 같은 CSS도 Json으로 받으면 적용이 안된다.

  • HTTP메소드에 POST, PUT처럼 Body에 data를 보낼때 Content-Type이 필요하다. 특정 data(img, viedo 등)를 Content-Type없이 보내면 data를 받는 쪽에서는 단순 텍스트 데이터로 받는다.

  • 서버에 요청을 보낼 떄도 사용된다!
    - 예를 들어, request로 Json형태를 보낼 때, header에 application/json으로 표시한다.
    - 요청 내에서, (POST 혹은 PUT처럼), 클라이언트는 서버에게 어떤 유형의 데이터가 실제로 전송됐는지를 알려줍니다.

HTML 폼 전송으로 일어나는 POST 요청 내에서, 요청의 Content-Type은 form 요소 상의 enctype 속성에 의해 지정됩니다.

<form action="/" method="post" enctype="multipart/form-data">
  <input type="text" name="description" value="some text">
  <input type="file" name="myFile">
  <button type="submit">Submit</button>
</form>

6월 21일

SPA, CSR, SSR, SSG, TTV, TVI

참고 서버사이드 렌더링 영상

  • 1990년 대까지만 해도 static site. HTML 만 사용. 단점: HTML 문서 통째로

  • 1996년부터는 iframe 태그로 부분적으로만 받아올 수 있다.

  • 1998부터: XMLHttpRequest API 개발 => JSON과 같은 포맷으로 서버에서 가볍게 필요한 데이터만 받아온다.

  • 2005: 위 방식이 AJAX라는 공식적인 방법으로. 이 방식으로 웹 애플리케이션 개발. 이것이 바로 SPA(싱글 페이지 어플리케이션) => 한 페이지에 머무르면서 필요한 부분만 부분적으로 업데이트 => 웹 사용성 향상

  • CSR(클라이언트 사이드 랜더링= 약간 인터페이스 느낌??): pc 성능 향상, JS 프레임워크의 발전으로 도입
    - 서버에서 다 처리하는 것을 말한다.

    • 서버에서 받은 HTML에 그냥 JS 파일만 덩그라니 있다. 그래서 비어있는 화면
    • 그리고나서 다시 또 JS 파일을 받는다. 추가로 필요한 데이터들은 다시 서버에 요청해서 사용자에게 최종적인 애플리케이션을 보여준다.
      - 단점
      - 1. 초기 로딩 시간 과다.
      - 2. 좋지 않은 SEO(검색엔진 옵티마이제이션): 검색엔진이 HTML 분석할 때 어려움
  • SSR(서버 사이드 랜더링): 웹사이트에 접속하면 서버에서 필요한 데이터들을 모두 가져온다.

    • 추가적으로 HTML 요소를 동적으로 약간 제어할 수 있는 소스코드 부여
    • CSR사용 때보다 페이지로딩 빠름. 모든 컨텐츠가 HTML에 담겨져있어서 효율적인 SEO
    • 단점: static sites 떄와 동일하게 blinking issue. 서버 과부화 가능성. HTML을 받아왔는데, 아직 JS 부분을 다 받아오지못해서 클릭해도 반응이 없을 수도.
  • SSR의 3번째 단점을 이해하려면 TTV(Time to view), TTI(time to interact)을 이해할 필요가 있다. TTV는 사이트를 볼 수 있는 시간, TTI는 사용자와 인터렉션할 수 있는 시간
    - CSR은 TTV와 TTI가 동시에. SSR은 TTV가 먼저, TTI는 이 후에.

    	==> CSR은 일단 필요한 부분만 먼저, SSR은 단차를 어떻게 좁힐 지 고민하라.
  • SSG(Static Site Generation):
    - 리액트는 CSR에 최적화된 프레임워크지만, Gatsby와 함께 활용하면 리액트로 만든 애플리케이션을 정적으로 미리 만들어서 서버에 배포해놓을 수 있다. 동적인 요소도 물론 함께 추가 가능
    - Next.js(갯츠비 다음으로 많이 사용): 강력한 SSR을 지원. 요즘에는 SSG, CSR+SSR 지원

===> 어떤 것이 정답이기보다는 우리 사이트가 정적/동적인지, 얼마나 자주, 많은 사용자가 있는지에 따라 유연하게 섞으면서 개발해나가시라.

6월 22일

custom exception

  • 현재 라이징캠프에서 baseException이라는 custom exception을 활용하고 있다. 그래서 서비스 특성에 맞게 예외처리하는 것에 궁금해졌다.

참고 링크
그림 출처

  • 클라이언트에 error type, error code, error msg를 전달해서 정확히 어떤 에러가 발생했는지 알려준다.

Exception 예외 클래스의 계층 구조

  • 문법적인 에러는 컴파일시 대부분 수정이 가능하다. 실행에러는 컴파일은 수행되었으나 실행시에 문제가 되는 경우다.

  • Exception 구조
    - 대부분 super(). throwable에서 처리한다.

  • Throwable 구조
    - 해당 클래스 타입의 이름과 msg 출력

  • HttpStatus

    • enum 클래스이다. 이는 서로 관련있는 상수들을 모아 심볼릭한 명칭의 집합으로 정의한 것, 즉 클래스처럼 보이게 하는 상수

    • series는 어떤 타입의 에러인지를 나타낸다.

    • 해당 에러코드의 의미를 나타내는 resasonPhrase

  • Custom Exception
    • error type: HttpStatus의 reasonPhrase
    • error code: HttpStatus의 value
    • msg : 상황별 디테일 msg
public class DanielException extends Exception {
	
    // 직렬화를 위한 
    private static final long serialVersionUID = 42577772L;

    private Constants.ExceptionClass exceptionClass;
    private HttpStatus httpStatus;

    public DanielException(Constants.ExceptionClass exceptionClass, HttpStatus httpStatus,
        String message) {
        super(exceptionClass.toString() + message);
        this.exceptionClass = exceptionClass;
        this.httpStatus = httpStatus;
    }

    public Constants.ExceptionClass getExceptionClass() {
        return exceptionClass;
    }

    public int getHttpStatusCode() {
        return httpStatus.value();
    }

    public String getHttpStatusType() {
        return httpStatus.getReasonPhrase();
    }
// 객체 리턴
    public HttpStatus getHttpStatus() {
        return httpStatus;
    }

  • HttpStatus 상태 코드
    • HttpStatus.java에 이미 정의되어있다.
    • 코드 번호는 getValue()로 가져올 수 있다.

==> 라이징캠프에서 진행했던 것은 HttpStatus를 따로 정의해주었던 것이다.


예외가 사용되는 ExceptionHandler

 @ExceptionHandler(value = DanielException.class)
    public ResponseEntity<Map<String, String>> ExceptionHandler(DanielException e) { // 예외를 받아온다. 
        HttpHeaders responseHeaders = new HttpHeaders();

        Map<String, String> map = new HashMap<>();
        map.put("error type", e.getHttpStatusType());
        map.put("error code",
            Integer.toString(e.getHttpStatusCode())); // Map<String, Object>로 설정하면 toString 불필요
        map.put("message", e.getMessage());

        return new ResponseEntity<>(map, responseHeaders, e.getHttpStatus());
    }
  • return 되는 값은 ({에러 타입, 에러 코드, 메시지}, HttpHeader객체, HttpStatus객체)

어떻게 사용되는가?

@PostMapping(value = "/product/exception")
    public void exceptionTest() throws DanielHubException {
        throw new DanielException(ExceptionClass.PRODUCT, HttpStatus.FORBIDDEN, "접근이 금지되었습니다.");
    }
    

아래와 같이 Product, Sign 등 도메인별로도 exception의 종류를 정의할 수 있는 듯하다. 출력될 때, msg가 "Product Exception. @@가 발생했습니다." 로 정의되는 것이다. 이를 통해 어디서 에러가 발생했는지를 알 수 있다.
==> BaseException은 code번호를 커스텀할 수 있는 있지만 어느 도메인에서 진행하는지 구별이 어려웠다. 그래도 BaseException<>(@@@) 로 나타낼 수 있던 것은 장점이다.


public class Constants {

    public enum ExceptionClass {

        PRODUCT("Product"), SIGN("Sign");

        private String exceptionClass;

        ExceptionClass(String exceptionClass) {
            this.exceptionClass = exceptionClass;
        }

        public String getExceptionClass() {
            return exceptionClass;
        }

        @Override
        public String toString() {
            return getExceptionClass() + " Exception. ";
        }

    }

}
  • HttpHeaders 클래스
    => 내일 ResponseEntity를 공부하면서 익히자.

6월 23일

ResponEntity

참고
1. 링크
2. HTTP header와 body
3. Spring io ResponseEntity

Spring MVC 로 마지막 프로젝트를 진행할 때 때, 리턴값은 Object와 View 뿐이었다 . Header 값을 통해 조금 더 견고한 API를 개발했더라면 더 좋았을걸 이라는 아쉬움이 남았다.

ResponseEntity란?

public class HttpEntity<T> {

	private final HttpHeaders headers;

	@Nullable
	private final T body;
}
  • Spring Framework에서 제공하는 클래스 중 HttpEntity라는 클래스가 존재한다. 이것은 HTTP 요청(Request) 또는 응답(Response)에 해당하는 HttpHeader(body, req, res에 대한 정보)와 HttpBody(실제 데이터 컨텐츠)를 포함하는 클래스이다.

  • HttpEntity 클래스를 상속받아 구현한 클래스가 RequestEntity, ResponseEntity 클래스이다. ResponseEntity는 사용자의 HttpRequest에 대한 응답 데이터를 포함하는 클래스이다.

  • 따라서 HttpStatus, HttpHeaders, HttpBody를 포함한다.


출처: https://medium.com/codestorm/custom-json-response-with-responseentity-in-spring-boot-b09e87ab1f0a

느낀점

  • 위와 같은 방식으로 status와 message를 전달하여 클라이언트가 status에 따른 화면 처리를 용이하게 한다.
  • 클라이언트는 status code 번호만 있으면 되는데, message는 이게 무슨 status인지 이해시켜준다.
  • 그리고 서버 쪽에서는 어느 쪽에서 문제가 발생한지 쉽게 파악 가능하다.
  • 꼭 ResponseEntity를 사용하지않더라도 Custom 해서 사용해도 된다. 공통적인 부분인 3가지만 있으면 될듯 싶다.
    1. 기존의 return 타입을 포함해서 ResponseEntity<@@> 혹은 BaseResponse<@@> 등이 return 타입된다.
    2. 클라이언트가 이해하기 쉽도록 message를 포함한다.
    3. 클라이언트 화면 처리와 문제 발생 위치를 알 수 있도록 Status Code를 담는다.

6월 24일(애플의 2022 WWDC)

PWA

  • 참고 애플의 2022 WWDC

  • 이전에는 지리 위치, 카메라, 연락처 정보, 블루투스, 파일시스템 등에 접근하려면 앱을 설치해야했다.

  • 하지만 현재는 위의 기능들을 다 JS을 통해 웹 브라우저에서 가능하고, PWA(progressive web application)으로 모바일 웹처럼 보이는 사이트를 통해 진행한다.

  • 앱 스토어에서 설치하는 것들은 앱이 아니라 바로가기 였다!

  • 이를 실행하면 웹 브라우저가 열리는데, PWA이기 때문에 브라우저 탐색 표시줄이 숨겨져서 앱처럼 보일 것이다.

장점

  • 오프라인에서도 가능(미리 에셋을 폰에 저장)
  • 주기적 백그라운드 동기화 API: PWA가 열려있지 않더라도 데이터를 주기적으로 받아온다.
  • 진짜 앱처럼, 푸시 알림 가능(PWA의 매력포인트. PWA 열려있지않더라도)
  • 웹사이트이기 때문에 앱 스토어에서 심사가 필요없다.

단점

  • 안드로이드에서는 잘 작동 but not ios.
    - 애플은 PWA의 성능에 위협을 느낌. 수수료로 장사하고 있는데...
    - IOS는 브라우저 엔진을 모두 제어하기에 PWA에 필요한 기능이 느리고, 푸시알림 기능을 막아놨다.

==> 그런 애플이 이제 2023년부터 푸시 알림에 필요한 API들을 구현할 것이라 발표


Passkeys(비밀번호가 없는 세상)

  • 거대 IT기업들은 비밀번호 없애기에 착수했다.

  • 애플은 Passkeys 기술을 발표했는데, 이는 비밀번호 없는 인증을 제공하는 기술이다.

  • 비밀번호 방식의 문제점
    - 유저들의 비밀번호의 재사용
    - 피싱의 대상

    • 가짜 웹사이트로 아이디, 비번 탈취
    • SIM 스와핑(인증코드에 사용될 휴대폰 번호 방식 해킹)
  • 계속 해결하고자 노력했으나 모두 완벽한 방법들이 아니었다.

  • FIDO(Fast Identity Online)
    - 비밀번호 사용을 줄이기위한 표준을 만드는 단체

    • 이 표준은 바로 구글, 애플, MS가 하기로 한 표준이며, passkeys는 애플이 이를 충족하기위한 표준이다.
  • Passkeys를 사용하게되면 이미 동기화된 휴대폰과 컴퓨터에서 QR 코드를 통해 Touch ID(혹은 Face Id) 로그인
    ==> 털릴 위험, 피싱의 위험이 없다. 컴퓨터와 휴대폰이 근접해야한다.

원리

  • Passkeys로 로그인하기 위해 QR코드 스캔하면, 디바이스는 공용 키와 개인 키를 생성한다. 개인 키는 개인 디바이스에, 공용 키는 서버에 남는다.
  • 개인 키에서 공용 키를 가져올 수 있지만, 그 반대는 안 된다.
  • 개인 키는 절대 서버로 가지않는다.
  • 로그인을 할 때, 공용 키에 과제를 담고, 개인 키는 이를 풀 수 있는 유일한 방법이다. 답변이 서버로 전송되면 로그인된다.
  • 즉, 서버에서 자물쇠를 주고, 개인 키는 이를 풀어서 열린 자물쇠임이 증명되면 로그인되는 것이기에 개인 키가 전송되는 방법이 아니다.

내 궁금증

  • 디바이스 잃어버리면 개인 키는 어떻게?
    => 비대칭키에 대해서 알아보시면 궁금증이 풀리실거 같아요

사람들 댓글

보안 절차가 점점 단순하면서 강화되고 특정 기업에 종속되지 않고 범용성이 커지고 있는 추세군요

앱에서 웹화면을 보여주는 하이브리드앱은 이미 흔하고 이렇게 하면 푸시도 쓸 수 있어서 PWA가 아니라도 방법이 없는건 아니었습니다만, 세계적인 OS들의 한 축이 웹에대한 지원을 제공한다는건 좋은 일이라고 생각합니다. 애초에 안드로이드와 iOS앱을 따로 만들고 따로 관리하는건 비용이 너무 많이 들어가고 무엇보다도 비효율적입니다.

앱푸시가 앱을 개발하는데 중요한 이유중에 하나이긴하나 하이브리드앱이 결국 주류가 되지 못한것 처럼, 편의성(스토어), 서드파티앱과의 연동성 등 네이티브앱의 장점들을 넘어서거나 비슷하게 구현할 수 없다면 역시 돌고돌아 네이티브는 살아 남을 수 있을것 같습니다
하지만, 반대로 이런 기능들이 필요없고 정말 ~ 앱푸시 하나만 있는 앱을 만든다거나, 플랫폼을 만드는 사업에 대해서는 PWA가 다시 한번 게임체인저로 부상할 순 있겠네요!

결국 고유한 유니크 키를 전세계 모두에게 부여하고 그 키의 생성권한을 완전히 글로벌 대기업만 가짐으로서 영구적인 우위를 시도하는거같네요. 카카오 없으면 민원결과 볼수없는 한국이 그런상태죠

휴대폰의 소유주임을 인증하기위해 생체인증같은 방법을 사용해야할텐데, 생체인증의 경우 한번해킹당하면 그 소스를 변경할수 없기 때문에 개인적으로 위험한 방법이라 생각하고있습니다. 패스워드의 경우 해킹당하면 바꾸면되지만, 지문이나 얼굴정보는 해킹당하면 바꿀수없기 때문이죠..(지문을 바꾼다거나 성형을한다거나..?)

0개의 댓글