Regular Motion

개발자가 상팔자

Category: general (page 1 of 19)

What the .,.,., ICP

중국에 웹 서비스를 런칭하기 위해 꼭 필요한 것 중에 ICP License라는게 있다.  한국과 같이 민주주의가 잘 정립되어 있고??, 세계화를 받아들인 국가?에서 개발하던 서민들은 쉽게 이해하기 어려운 부분인데 중국에서 웹 서비스를 런칭하기 위해 꼭 필요한 것이니 한번 알아보자.

 

그렇다면 먼저 ICP License란 무엇인가?

ICP는 Internet Content Provider의 약어로써 Mainland China에서 서비스되는 모든 웹 서비스들이 반드시 발급 받아야 하는 License로써 중국의 Ministry of Industry and Information Technology(한국의 미래창조과학부 구 정보통신부 정도 되는 기관이 아닐까 생각된다)에서 발급을 주관하며 발급받은 ICP License 번호는 홈페이지의 Footer에 노출하는게 일반적이다.

* 대부분의 호스팅 업체가 가입 단계에서 ICP License 번호를 입력받는 경우가 많고, AWS China의 경우 ICP License 없는 계정은 Public 서비스를 할 수 있는 Port를 모두 막아 놓는다.

이런 전근대적인 정책은 2000년 9월 Telecommunications Regulations of the People’s Republic of China에서 공표했다고 전해진다.

 

ICP License에는 어떤 종류가 있는가?

  • ICP License: 상업적인 웹사이트를 위한 ICP로써 홈페이지내에서 상품 판매가 이루어 진다면 반드시 ICP License를 발급 받아야 한다. 다음과 같은 형태를 갖는다. (京ICP证12345678号)
  • ICP Filing: 비상업적인 웹사이트를 위한 ICP로써 홈페이지에서 상품 판매를 할 수 없고, 정보 제공을 목적으로 하는 홈페이지에 적합한 ICP라고 할 수 있다. 다음과 같은 형태를 갖는다.  (京ICP备12345678号) (가운데 한자가 하나 다름에 주의하자 ICP Recordal 이라고도 많이 부른다)

 

ICP License는 어떻게 발급 받을 수 있는가?

여기서 부터는 실전이다. 해석하자면 나도 해본적이 없다는 뜻이다.

* 홈페이지 개발사가 직접 MIIT(Ministry of Industry and Information Technology)에 ICP Application Form을 제출하는게 아니라, ISP 또는 호스팅 업체를 통해 진행되는 부분에 주목하자.  한자에 서툰 개발자를 긍휼이 여기사 중간에 대행 업체가 끼는 것 같다. 한줄기 작은 빛

 

AWS China 또는 Alibaba Cloud를 이용 할 때는 어떻게 ICP License를 발급 받을 수 있는가?

AWS China 또는 Alibaba Cloud의 설명을 따르면, AWS China의 경우 Sinnet이 ICP 발급과 관련된 업무를 대행해주는 역할을 한다고 한다. 나도 해본적이 없으니 아래 링크를 참고하자.
http://en.sinnet.com.cn/home/service/records/55
https://www.amazonaws.cn/en/about-aws/china/faqs/ 

 

끝으로 중국에서 서비스하다 크게 데인 것 같은 형은 아래와 같은 말을 남겼다.

Internet laws in China change all the time, and what’s true today may not be true tomorrow.

 

References

 

Small Tips When You Develop Chrome Extension

  • Content Scripts가 Inject되는 타이밍을 정의 할 수 있다.
    manifest.json의 content_scripts의 속성 중 run_at 속성으로 content_scripts 파일이 Inject되는 시점을 정의 할 수 있다. run_at의 값으로는 document_start, document_end, document_idle 세가지가 올 수 있다. 기본으로 document_idle이 적용되며 Inject되는 시점은 아래와 같다.

      • document_start: DOM이 생성되기전 또는 다른 Script들이 실행되기전에 Script가 Inject 된다. Inject하려는 Script가 1빠로 실행되어야 하면 이 타이밍을 노려보자.
      • document_end: DOM 생성이 완료 된 후, Script가 Inject된다.
      • document_idle: document_idle은 시점이 불명확한데, document_end 이벤트와 window.onload 이벤트가 Fire된 직후 그 사이에 Script가 Inject 된다. 따라서 document_idle로 Inject되는 경우 window.onload 이벤트를 받지 못 할 수 있다.

    * 예전에 Supreme 자동구매 봇을 만든적이 있는데, (참고로 Supreme의 인기 신상은 1~2초 싸움이다) run_at:document_idle에서 제품을 담고, 결제하도록 했을 때와 run_at:document_end:에서 제품을 담고, 결제하도록 했을 때의 성공 확률이 크게 차이났었다.

 

  • Content Scripts는 Web Pages의 DOM에 접근 및 제어가 가능하나, JavaScript Context는 별도로 존재한다.
    Web Pages와 Content Scripts는 각각 별도의 JavaScript Scope를 갖기 때문에, Content Script에서 Web Pages의 변수나 함수를 사용 할 수 없고, Web Pages에서도 Contents Scripts의 변수나 함수에 접근 할 수 없다.  허나  Content Scripts에서 Web Pages의 DOM에 접근 및 제어가 가능하다.  DOM을 제어 할 수 있다는 사실은 실로 대단한 가능성을 내포하고 있다.

 

  • Content Scripts는 Chrome Extension의 Popup과 Background Scripts와 localStorage를 공유하지 않는다.
    localStorage도메인 별로 독립된 저장공간을 사용한다. Content Scripts는 Web Pages와 같은 도메인에서 실행되고, Popup과 Background Scripts는 chrome-extension://으로 시작하는 도메인에서 실행된다.  따라서 Content Scripts와 Popup, Background Scripts는 localStorage를 통해 데이터를 공유 할 수 없다.
    * 글로 적으면 당연한 사실인데 만들다보면 왠지 공유가 될 것 같다. 희망은 이성을 초월하는 것 같다.만약 반드시 Content Scripts와 Popup, Background Scripts간 데이터를 저장/공유해야 한다면 localStorage 대신 chrome.storage를 사용해야 한다. * 알 수 없는 이유로 10분을 허비하기 싫으면, manifest.json의 permissions에 storage 추가하는 것을 잊지 말자.
    사용법은 https://developer.chrome.com/extensions/storage#property-sync 링크를 참고하면 쉽다;localStorage와 다르게 개발자 도구에서 Inspect/Edit를 제공하지 않는다. (2017/05 기준) 만약 chrome.storage를 Heavy하게 사용 할 예정이라면, Storage Area Explorer를 설치해서 사용해야 한다. 아직 정품이 없다.

 

  • Again, Content Script는 Web Pages의 DOM에는 접근/제어가 가능하나, JavaScript Scope는 별도로 존재한다.
    만약, Web Pages에서 필요한 JavaScript 코드가 있다면 Script Element를 이용해 File 또는 Text를 Inject 하는게 제일 편하다.아래의 코드를 통해 File 또는 Text를 Inject 할 수 있고, Inject 하려는 파일은 manifest.json의 web_accessible_resources에 선언되어야 한다. web_accessible_resources에 선언된 파일에 한해 Web Pages에서 접근 가능하다.

     

AWS S3 Transfer Accelerator

AWS의 S3는 Static한 파일을 저장/배포하기에 매우 훌륭한 저장소지만, 버킷의 Region이 접속지역과 멀리 떨어진 경우 응답시간과 전송시간 모두 사용자들의 인내심을 테스트하게 만드는 단점이 있다. 사실 다운로드의 경우 CDN(CloudFront)을 이용해 개선 할 수 있지만, 업로드는 방법이 없다.

현재 회사에서 운영중인 서비스는 유럽에 위치한 주요 고객(이라 적고 갑이라 읽는다)을 위해 대부분의 버킷을 eu-west-1에 위치시키고 있다.  eu-west-1의 버킷의 경우 100KB의 파일을 업로드/다운로드하는데 1~3초, 5MB 정도의 파일은 수십초가 소요된다.  (편리함의 대가로 시간을 지불하고 있었던 것이다).

매일같이 시간을 지불하고 있던 어느날, S3에 Transfer Acceleration을 활용하면 적게는 2~3배에서 많게는 10배 정도 업로드/다운로드 속도가 빨라진다는 글을 접하게 됐다.  평소 의심이 많고, 두눈으로 보기전엔 믿지 않는 분들은 AWS에서 제공하는 속도비교 페이지에 접속해보시기 바란다.  7번 정도 확인을 해봤는데 eu-west-1의 경우 6~21배 정도 속도차이가 있었다.

이제 Transfer Acceleration의 효과를 봤으니, 1) 속도 개선이 어떻게 이루어지고 2) 적용 방법은 어떻게 되며 가장 중요한 그래서 3) 얼마를 더 내야 되는지 알아보자.

Overview

공식 설명은 ‘S3 Transfer Acceleration은 AWS S3로 데이터를 전송 할 때, AWS의 Edge 인프라와 네트워크 프로토콜을 최적화하여 전송 속도를 개선하는 기능’ 이라고 되어 있습니다.

사용자가 S3 Bucket에 데이터를 전송 할 때, 직접 Origin 서버로 전송하는게 아니라 AWS의 Edge 인프라를 활용하여 사용자는 가장 가까운 Edge 서버로 데이터를 전송하고, Edge 서버에서 Origin 서버로 최적화된 네트워크 프로토콜과 전용회선을 활용하여 데이터를 전송함으로써 속도를 개선합니다. 그림으로 표현하면 아래와 같습니다.

Before

After

자칫 복잡해 보일 수 있는 아래의 방식이 5~10배 이상 빠르다는건 Edge 서버와 S3 사이의 네트워크 프로토콜과 데이터 이동이 최적화되었다는 반증일겁니다. 실제로 Edge 인프라를 활용하기 위해 Transfer Acceleration을 사용하는 요청은 Endpoint가 기존과 다릅니다.

  • Original Endpoint: https://{your-bucket}.s3.amazonaws.com/
  • Accelerated Endpoint: https://{your-bucket}.s3-accelerate.amazonaws.com/

 

버킷에서 Transfer Acceleration 설정

Transfer Acceleration은 Bucket 레벨에서 적용할 수 있는 기능이기 때문에, 적용을 원하는 버킷의 속성에서 Transfer Acceleration을 활성화(Enable)해주면 됩니다.  활성화 방법은 아래 세가지 방법 중 평소 본인이 흠모하던 방법으로 하시면 됩니다. 자세한 방법은 링크를 참고하시는게 글을 쓰는 사람과 읽는 사람 모두의 정신건강에 이로울 것 같아 링크로 대체합니다.

Transfer Acceleration 활용

아쉽게도, 버킷에서 Transfer Acceleration 속성을 활성화하는 것으로 갑자기 빨라지는 건 아니고, 버킷에 파일을 업로드/다운로드를 하는 부분도 약간의 수정을 해야 합니다. SDK를 사용하고 있었다면 Flag를 활성화하는 수준이고, REST API를 사용하고 있었다면 Endpoint를 대체하는 수준으로 가능합니다. (역시나 우리 모두의 정신 건강을 위해 링크로 대체합니다)

Transfer Acceleration 비용

저장 비용에는 변화가 없으며, Transfer Acceleration을 이용한 전송에 추가 비용이 발생합니다. GB당 추가로 $0.04가 부과됩니다. (스벅에서 카페라떼 한잔을 참으면 약 100GB를 빠르게 전송 할 수 있습니다. 반대로 100GB를 느긋하게 전송하면 카페라떼를 한잔 사먹을 수 있습니다)

Benchmark Test

평소 의심이 많던 저는 AWS의 속도 비교 페이지를 온전히 믿지 못하고, 직접 벤치마크 테스트를 해봤습니다. 아래 표는 eu-west-1 버킷에 CLI를 이용하여 파일을 업로드/다운로드한 결과입니다. 파일의 크기가 크면 클수록 속도 개선이 드라마틱하게 이루어짐을 알 수 있습니다. 15MB 정도되는 파일의 경우 평균 43초 정도 소요되던 다운로드 속도가 4.7초로 개선된 것을 확인 할 수 있습니다.

 

주의사항
  • 설정 후 반영까지 최대 30분정도가 소요 될 수 있습니다.

Common Design Patterns for Android

이 글은 https://www.raywenderlich.com에 소개된 글을 저자의 동의를 얻고 번역한 것임을 알려드립니다.

개발자로서 일하며 행복을 유지하기 위해서는 고객과 사장님도 만족시켜야 하지만, 미래의 나 또한 만족시켜야 한다.  (행복한 닭이 더 맛있는 달걀을 낳는다고 하지 않던가)

미래의 나는 과거의 내가 작성한 코드를 이어받게 될 것이고, 아마 왜 이렇게 코드를 작성했는지 궁금해 할 것이다.  헷갈리는 주석을 왕창 달아 놓는 것보다, 많이 사용되는 디자인 패턴을 적용하여 코드를 읽기 쉽고, 구조화 시켜 놓는게 미래의 나를 위해 훨씬 나은 방법일 것이다.

이 글은 안드로이드 개발을 하며 많이 사용하는 디자인 패턴을 소개 할 것이다. 디자인 패턴이란 일반적인 소프트웨어 개발시 마주 할 수 있는 문제들을 해결 할 수 있는 재사용 가능한 해결책이라고 할 수 있다. 이 글에서는 많은 디자인 패턴을 소개하지는 않을 예정이지만, 시작점으로 좋은 글이 될 것이라고 생각한다.

Getting Started

“동일한 수정을 여러 곳에 적용해야 할 부분이 이 프로젝트에 있나요?” – Future You

미래의 당신은 아마 추측하거나 추론하며 프로젝트의 의존성을 찾는 시간을 최소화하고 싶을 것이다. 그러기 위해 프로젝트는 최대한 재사용 가능하며, 읽기도 쉽고, 이해하기 쉬워야 할 것이다.  하나의 클래스부터 전체 프로젝트에 이르기까지 위 목표를 달성하기 위해, 패턴을 다음의 카테고리로 나눌 수 있다.

  • Creational patterns: how you create objects.
  • Structural patterns: how you compose objects.
  • Behavioral patterns: how you coordinate object interactions.

당신은 아마 각각의 패턴을 지칭하는 이름을 모른채 몇 종류의 패턴들은 사용하고 있을지도 모른다. 이제 각각의 카테고리에 어떤 패턴이 있으며 실제로 Android에 어떻게 구현/적용 할 수 있는지 알아보자.

Creational

  • Builder
  • Dependency Injection
  • Singleton

Structural

  • Adapter
  • Facade

Behavioral

  • Command
  • Observer
  • Model View Controller
  • Model View ViewModel

Creational Patterns

“복잡한 오브젝트가 여러곳에서 필요할 때는 어떻게 하죠?” – Future You

미래의 당신은 위 물음에 “동일한 코드가 필요할 때마다 Copy and Paste하면 되잖아요?” 라는 말을 듣고 싶지는 않을 것이다.  대신 Creational Pattern으로 오브젝트의 생성을 단순하게 유지하고 쉽게 반복 가능하도록 만들 수 있습니다.

Builder

단골 샌드위치 가게의 주문서에 빵의 종류와 재료 그리고 양념을 펜으로 선택한다. 주문서의 이름이 “Build my own”이지만 실제로 샌드위치를 직접 만들지는 않고 입맛에 맞게 각각의 재료들을 선택한 뒤 직원에게 넘겨 줄 뿐이다.

이와 비슷하게 Builder pattern은 Object의 복잡한 생성과정(빵을 익히고 자르고, 재료를 넣고, … )을 Object(샌드위치)에서 분리한 것이다. 이와 같은 방법을 통해 동일한 프로세스로 다른 Object(샌드위치)를 쉽게 만들어 낼 수 있다.

Android의 AlertDialog.Builder와 같은 오브젝트에 Builder pattern이 사용된다.

위의 AlertDialog를 Build하는 과정은 단계적으로 진행되며, AlertDialog의 요소 중 수정하고 싶은 부분만 수정 할 수 있도록 해준다.  AlertDialog.Builder 문서를 보면, Alert을 만들 때 매우 제한적인 요소만 설정 할 수 있다는 것을 알 수 있다.

위 코드는 아래와 같은 Alert을 생성한다.

please_use_the_spicy_mustard

Dependency Injection

Dependency Injection은 빌트인 가구가 갖춰진 아파트로 이사하는 것과 비슷하다. 필요한게 이미 있기 때문에; IKEA 홈페이지에 접속해서 가구를 주문하고 배달을 할 필요가 없다.

소프트웨어 측면에서 보자면, Dependency Injection은 새로운 Object를 생성하는 시점에 필요한 Object들을 제공해준다. 따라서 새로 생성되는 Object는 필요한 Object들을 만들 필요가 없다.

안드로이드에서는 앱의 다양한 Activity 또는 Fragment에서 Network Client나 Image Loader, SharedPreferences와 같은 다양한 Object들에 접근 할 필요가 있다. Dependency Injection을 활용하면 이러한 Object들을 Activity나 Fragment들에 Inject 한 뒤, 필요한 시점에 바로 사용 할 수 있도록 해준다.

Dagger 2는 Google과 Square가 협업하여 개발한 Framework으로, Android에서 가장 유명한 Dependency Injection Framework이다. 클래스에 @Module 어노테이션을 추가한 뒤, @Provides 어노테이션으로 필요한 모듈을 제공하도록 할 수 있다.

위 모듈은 Object 생성과 필요한 설정을 수행한다. 규모가 있는 앱을 위한 Best practice로는, 여러 모듈을 함수로 구분하여 생성 할 수도 있다. Component interface를 만든 뒤, Inject가 필요한 모듈과 클래스를 나열한다.

Component는 dependency들이 어디서 와야(module coming from) 되고 어디로 가야(injection point) 되는지를 판단하여 묶어 주는 역할을 한다.

마지막으로 @Inject 어노테이션을 사용해서 Dependency가 필요한 곳에 삽입 할 수 있다.

* Dagger에 대한 간소화된 개요이기 때문에, 자세한 내용은 Dagger 문서를 참조하기 바란다.

Singleton

Singleton 패턴은 클래스의 인스턴스가 오직 하나만 생성되도록 해준다. 모델링하는 Object가 실제로 단 하나의 인스턴스만 갖을 때, Singleton 패턴은 잘 동작한다.

위 ExampleSingleton 클래스는 객체의 생성자를 static 함수인 getInstance() 함수 안으로 숨겨서, 객체가 하나만 생성되도록 보장한다. Singleton 객체에 접근이 필요할 때는 아래와 같이 getInstance() 함수로 접근 할 수 있다.

Singleton은 이해하기 가장 쉬운 패턴 중 하나지만, 오/남용되기 가장 쉬운 패턴이기도 하다.  복수의 객체에서 동일한 Singleton 인스턴스에 접근 할 수 있기 때문에 예상치 못한 Side Effect가 발생하기 쉽고, 원인을 파악하기 어려운 경우도 많다.  따라서 사용하기 전에 패턴을 정확히 이해하고 사용하는 것이 중요하다.

 

Structural Patterns

미래의 당신은 전형적인 작업(typical task)을 수행하는 클래스와 오브젝트들을 익숙한 형태로 정리 할 수 있도록 도와준 Structural Pattern을 의심의 여지없이 고마워 할 것이다. AdapterFacade는 안드로이드에서 가장 많이 사용되는 패턴이다.

Adapter

Apollo 13에서 엔지니어들이 네모난 마개를 ‘Round Hole’에 맞추는 유명한 장면이 있다. 이 장면은 Adapter의 역할을 은유적으로 보여준다. Adapter 패턴은 Class의 Interface를 변환하여 사용자가 예상하는 다른 Class의 Interface에 맞출 수 있도록 해준다.
(By converting the interface of a class into another interface the client expects).

당신 앱의 비즈니스 로직은 제품이 될수도, 사용자 또는 건조틀이 될 수도 있다. 그게 뭐가됐든, RecyclerView는 모든 Android App에서 공통으로 사용되는 ‘Round Hole’ 이다.

RecyclerView는 Star Trek의 에피소드를 하나도 본적이 없기 때문에 Tribble이 뭔지 모른다.  하지만 데이터를 처리하고, ViewHolder에 데이터를 올바르게 전달해주는 Adapter의 역할을 한다.

Facade

Facade 패턴은 인터페이스들의 모음을 사용하기 쉽게 하기 위한 Higher-level 인터페이스를 제공한다. 아래 다이어그램은 이를 더 자세히 설명해준다.

만약 Activity에서 도서 목록이 필요하다면, 내부 저장소나 캐시 그리고 API 클라이언트의 내부 로직에 대한 이해 없이도 요청 할 수 있어야 한다.  이는 Activity와 Fragment의 코드를 깨끗하고 간결하게 유지하는 것을 넘어 Activity에 영향을 주지 않고, API 구현에 대한 변경사항을 적용 할 수 있도록 해준다.

SquareOne의 Retrofit은 Facade 패턴을 구현할 수 있도록 도와주는 Open Source Android 라이브러리다. API data를 제공하는 Interface를 아래와 같이 생성하면,

Client에서는 listBooks()을 호출하는 것 만으로 도서 목록을 얻어 올 수 있다.  RequestInterceptor 또는 OkClient의 설정을 수정(customize)하는 것 만으로 Client의 변경없이 캐시 동작 방식을 제어 할 수 있다.

Behavioral Patterns

Behavioral 패턴은 앱의 기능에 책임을 부여 할 수 있도록 해준다. Behavioral 패턴을 통해 프로젝트의 구조나 설계를 파악하는데 도움을 얻을 수 있다. 이 패턴의 Scope는 두 객체간의 관계에서 부터 전체 어플리케이션의 구조에 이르기까지 다양하게 나뉜다. 다양한 Behavioral 패턴이 하나의 앱에 사용되는게 일반적이다.

Command

인도 음식점에서 ‘Saag Paneer’를 주문했을 때, 음식이 만들어지는 과정은 알 필요가 없다. 종업원에게 주문을 알려주기만 하면 된다.

이와 비슷하게 Command 패턴은 Request를 수신하는 곳에 대한 정보없이 발행 할 수 있도록 해준다.

Greenrobot의 EventBus는 Command 패턴이 아래와 같이 동작할 수 있도록 해주는 Android Framework다.

EventBus-Publish-Subscribe

EventBus의 실제 동작방식은 링크를 참고하기 바란다.

Observer

Observer 패턴은 Objects간의 1 대 多 의존성을 정의 한 뒤, Object의 상태가 변경됐을 때, 이에 의존적인 Object들에게 내용이 전달되고, 자동으로 갱신된다.

Observer 패턴은 활용도가 높아, API Call이나 사용자 입력에 대한 반응과 같이 종료시간을 예측하기 어려운 작업에는 모두 적용 할 수 있다.

RxAndroid Framework은 아래와 같은 방식으로 Observer 패턴을 앱에 적용 할 수 있게 해준다.

 

Should URL be case sensitive?

회사에서 회의 중 URL이 Case Sensitive하게 처리되어야 하는지에 대한 사실 확인이 필요하여 이를 찾아본 과정의 기록입니다.

결론부터 말하면 URL은 Case Sensitive 합니다.
(결론부터 알려드렸지만 끝까지 읽어주세요. 광고도 없는 걸요;)

아주 조금만 더 들어가서 우리가 URL이라고 말하는 건 크게 6가지 요소로 나눌 수 있습니다.

RFC 7230에 따르면, 위 구성요소 중 Scheme와 Host를 제외한 요소들은 Case Sensitive하게 처리되어야 합니다.
(Port는 숫자로만 구성되니 논외로 합시다)

 

시작부터 비교적 명확하게 결론이 났습니다.  Scheme와 Host를 제외한 요소들은 Case Sensitive하게 처리되어야 한다.

즉,  https://www.google.com/HTTPS://WWW.GOOGLE.COM/은 완전히 동일한 결과를 보장하지만,  https://www.google.co.kr/search?query=new와 https://www.google.co.kr/search?query=NEW는 다른 URL로 볼 수 있고, 실제로 검색결과도 미세하게 다릅니다.

 

어허,  근데 실제로 대부분의 사람들이 URL을 입력 할 때 대/소문자를 의미있게 구분해서 사용하고 있을까? 라고 자문해보면  ‘아니오‘라고 말 할 수 있습니다. 대부분의 사람들은 소문자만으로 URL을 입력하고 있고, URL에 대문자가 섞여 있다면 아마 Caps lock을 의심해봐야 합니다.

RFC 규약의 scheme와 host를 제외한 요소는 Case Sensitive하게 처리돼야 한다는 사실과는 별개로 실제 URL에 대소문자를 의미있게 섞어서 사용하는 사람이 거의 없다고 할 때,  HTTP://WWW.EXAMPLE.COM/LIST로 접속한 사용자에게 http://www.example.com/list의 결과화면을 보여주지 않을 이유가 없습니다.

실제로 많은 서비스들에서는 Scheme와 Host를 제외한 요소에 대해서도 Case Insensitive하게 URL을 처리하고 있습니다.  믿지 못하는 분은 아래 2개의 링크를 클릭해보시길 바랍니다. 동일한 페이지를 나타내는 걸 알 수 있습니다.

http://stackoverflow.com/questions/7996919/should-url-be-case-sensitive

HTTP://STACKOVERFLOW.COM/QUESTIONS/7996919/SHOULD-URL-BE-CASE-SENSITIVE

 

다시 처음으로 돌아가서 그래서 URL은 Case Sensitive한가? 또는 Case Sensitive하게 처리되어야 하는가?

RFC에 따르면 Scheme와 Host를 제외한 요소들은 Case Sensitive하게 처리되어야 한다. 허나; 서비스에서 Path와 Query, Fragment의 대소문자 구분이 크게 의미가 없을땐 알아서 잘 하자잉.

 

References

 

Older posts

© 2017 Regular Motion

Theme by Anders NorenUp ↑