미디어로그

본 포스트는 iphone 애플리케이션에 springnote를 서비스 프로바이더로 한 oauth인증을 적용하는 과정에 있었던 이슈들을 중심으로 합니다.
이미 스프링노트를 개발하신 deepblue님께서 제가 약간 어려워 했던 부분에 대해서 잘 정리를 해주셔서, 여기서는 간단히 적어볼까 합니다.

OAuth를 통한 파일 전송
OAuth는 기본적으로 프로바이더와 컨수머간의 인증에 쓰이는 SBS(Signature Base String)은 application/x-www-url-form-encoded 파라미터만을 염두하고 있습니다. 따라서 파일 전송을 할때 쓰이는 multipart/form-data는 인증파라미터로 쓰일 수 없습니다. 실제로 oauth메일링리스트를 보면 종종 나오는 것이 "oauth를 통해서 파일업로드를 하고싶은데 어떻합니까!?"라는 질문입니다. 안타깝게도 현재 스팩에서 해결책은 딱히 정해져 있지는 않습니다만, 나름의 해결책은 있습니다, 바로 POST, PUT 요청에 대해서 multipart/form-data요청을 할 경우에는 HTTPBody부분을 SBS로 포함시키지 않는 방법입니다.
IPhone의 경우 Objective-C를 사용하며, 다행히도 Objective-C OAuth Consumer library가 존재 합니다만, 아쉽게도 multipart/form-data 예외처리를 위한 패치는 찾아볼 수 없었습니다. 다행히 코드 몇줄로 바꿀 수 있었습니다.

NSMutableURLRequest+Parameters.m 의 patch 입니다.
38c38,42
<         encodedParameters = [[NSString alloc] initWithData:[self HTTPBody] encoding:NSASCIIStringEncoding];
---
>         if ( [[self allHTTPHeaderFields] valueForKey:@"Content-Type"] != nil && [[[self allHTTPHeaderFields] valueForKey:@"Content-Type"] hasPrefix:@"multipart/form-data"]){
>             encodedParameters = nil;
>         }else{
>             encodedParameters = [[NSString alloc] initWithData:[self HTTPBody] encoding:NSASCIIStringEncoding];
>         }

Objective-C에서의 HTTP PUT요청에 대한 미스테리
위의 패치를 만들고 멋지게 iphone에 있는 사진데이터를 업로딩시키고, 이제 스프링노트의 페이지 수정을 위해 NSURLConnection을 통해 HTTP PUT요청을 정확히 날렸습니다만, 계속 signature unauthorized문제가 일어났습니다.
문제는 뻔했습니다, SBS를 만드는 과정에서 잘못된 것일텐데, 분명히 이쪽에서 보내는 SBS는 문제가 없었습니다. 알고보니 서버쪽에서 HTTP Body를 받지 못하고 있었습니다. 꼼꼼하게 살펴봐도 전혀 요청쪽에는 문제가 없었고 그렇게 거의 2시간이 흘러버린뒤, 기어이 NSURLConnection에 대한 의심을 하기 시작했습니다.

설마...... 가 사람 잡았습니다.

NSURLConnection에서 PUT요청을 할경우 HTTP Body를 빠뜨리는 아주 오래된 버그가 있었습니다. 이 때문에, PUT요청을 회피하기 위하여 스프링노트가 레일스로 개발되어있다는 잇점을 십분 활용하여 _method파라미터를 이용하였습니다. 요청은 POST로, _method파라미터 값을 PUT으로 요청하면 레일스서버에서는 이 요청을 인자하게 PUT요청으로 받아들여줍니다.

하지만, 이 방법에도 약간의 함정이 있었습니다.

바로 SBS에 HTTP Method도 포함됩니다. 컨수머쪽에서는 POST로 요청했으므로 SBS에 들어가는 HTTP Method에는 당연히 POST가 들어가지만, 이 요청을 받는 레일스 서버에서는 PUT요청을 SBS에 넣고 인증을 한다는 것이죠. 인증실패가 납니다. 따라서 PUT요청을 할때 SBS를 생성시 HTTP Method를 POST로 넣어주는 추가 작업이 필요했습니다.

이로써 iphone에서의 스프링노트와의 oauth인증을 통한 페이지 CRUD와 첨부파일 업로드까지 모두 성공할 수 있었습니다. 브라보!

약간의 고생을 하긴 했지만, 재미있던 경험이었습니다.

Objective-C 다음에 어떤 난관이 있을지 기대됩니다. -_-+

추가적인 이슈들이 좀 있기는 합니다만, 이번 기점(iphone 개발 관련 포스팅)으로 블로그를 서비스형으로 옮길까 고민중이라. 다음 이슈는 새로운 블로그 환경에서 시작할까 합니다. 어짜피 혼자 주절거리는 블로그인지라 부담없이 옮길까 합니다. 어디가 좋을까요?~^^;
Posted by
springnoteopenAPI는 CRUD를 지원한다. CRUD는 4개의 Http Method과 1:1매핑이 된다.
즉, Create-POST / Retrieve-GET / Update-PUT / Delete-DELETE.
브라우저마다 다른 XHR객체사용의 불편은 openAPI을 한번이라도 사용해보았다면
느끼게 될 것이다. 이러한 불편(대표적으로 cross browser문제)을 해결하고, 좀더 깔끔한
Ajax코딩을 가능케하는 특색 있는 여러 library들이 있다. 그중에 가장 사용 비율이 높다는 Prototype.js에서는 XHR를 통한 비동기신 리모트 호출을 할때 쓰이는 Http 메소드를
POST와 GET만 고려하고 있다. springnote의 openAPI를 사용하기 위해 처음으로 Prototype.js를 적용하면서 발견한점이다. PUT과 DELETE메소드를 사용하도록 Prototype.js에 약간의 손을 대는 것은 의외로 간단하다. 2군데만 간단히 바꾸어주면 된다.
Prototype.js의 1000라인쯤(버전마다 다르기때문에 ctrl-f로 검색해보면 좋다.) 가보면 다음과 같은 코드가 있다.
  request: function(url) {
    this.url = url;
    this.method = this.options.method;
    var params = Object.clone(this.options.parameters);
    if (!['get', 'post'].include(this.method)) {
      // simulate other verbs over post
      params['_method'] = this.method;
      this.method = 'post';
    }
대충봐도 if안에서 PUT과 DELETE가 걸리게 된다는 것을 알 수 있다. 이부분에 추가!
  request: function(url) {
    this.url = url;
    this.method = this.options.method;
    var params = Object.clone(this.options.parameters);
    //★put, delete 추가
    if (!['get', 'post','put','delete'].include(this.method)) {
      // simulate other verbs over post
      params['_method'] = this.method;
      this.method = 'post';
    }

이렇게 되면 delete는 사용 가능하다!. 하지만 PUT(Update기능)을 하기 위해서는
POST에서와 같이 Postbody에 수정하고자 하는 XML혹은 JSON을 첨부해야 한다.
이를 위해서 해야할일이 있다. 1000라인 약간지나서 다음과 같은 부분을 찾을 수 있다.
this.body = (this.method == 'post')? (this.options.postBody || params) : null;
이부분에 PUT을 추가한다.
this.body = (this.method == 'post' || this.method == 'put')? (this.options.postBody || params) : null;
이렇게 되면 4가지의 메소드 모두를 쓸 수 있다.

이제 Authentication 설정해주기를 해보자. 이는 구글링을 통해 정보를 얻을 수 있었다.
이름하여 Prototype-Authentication patch. Springnote나 Me2day뿐 아니라 대부분의 OpenAPI의 Authenticaion은 HTTP Basic Authentication방식을 사용한다.즉 XHR.open할때 파라미터로 username과 password(각 openAPI제공측에서 규정하는 방식으로 생성한)
로 넘겨주면 끝이라는 것. prototype에서는 아쉽게도 이부분이 제공되지 않았다. 간단하게 코드 몇줄만 추가하면 가능하다.
1000줄 약간 지나서(1000줄 근처에 XHR호출 관련 메소드가 있기때문.) 다음과 같은 부분이 있을 것이다.
     
this.transport.open(this.method.toUpperCase(), this.url,
        this.options.asynchronous)
이부분을 지우거나 주석처리하고 다음과 같이 수정.
//this.transport.open(this.method.toUpperCase(), this.url,
//this.options.asynchronous);
    if (this.options.username && this.options.password){
        this.transport.open(this.method.toUpperCase(), this.url, 
        this.options.asynchronous, this.options.username,                   
        this.options.password);  
    }else{
        this.transport.open(this.method.toUpperCase(), this.url, 
        this.options.asynchronous);
    }
이렇게 해서 XHR에서의 PUT, DLETE메소드 사용과 Authentication을 편리하게 사용이 가능해졌다. 사용은 간단하게 다음과 같다. 다음은 Prototype.js를 사용하여 Springnote의 openAPI를 사용해서 Create할수 있는 XHR 호출부이다.
new Ajax.Request(encodeURI(p_url),{
        method : "post",
        contentType : 'application/xml',
        requestHeaders : ["Authorization",getSpringnoteAuth(this.user)],
        postBody : p_postBody ,
        onSuccess : function(xmlHttp){
            $('result').innerText = xmlHttp.responseXML.xml;
            var page = new PageInfo(xmlHttp.responseXML);   
        },
        onFailure : function(result){
            alert("Failed");
        },
        onException : function(result){
            alert("Exception occured");
        }
   });
p.s > Enjoy it~
Posted by
키링크님의 web2.0과 springnote에 관한 글을 읽고, 제가 생각하는 web2.0과 Springnote에 대한 생각에서 상이한 부분이 있어 글을 남겨 봅니다. web에 대한 큰 관심을 가지고 있는 학생의 twitter쯤으로 여겨주시면 좋겠네요. 저의 짧은 소견에 부족한 점이 있다면 언제든 trackback. 대환영입니다.

웹2.0의 또 다른 정의로 "성공한 웹 사이트의 공통 특징"라는 말이 있으니, 롱테일을 구축하지 못한 웹2.0 서비스는 웹2.0 이 아닌 것과 같다.

> 파레토(80:20)법칙에 대비되어 web2.0의 큰 특징 중 하나로 인정받는 키워드가 롱테일 법칙은 맞습니다만, 롱테일을 구축하지 못한 서비스가 웹2.0이 아니라고 하기에는 무리가 있지 않을까 생각 합니다. 1990년대말에 닷컴버블 이후에 살아남은 여러 사이트들이 특징적 키워드들이 web2.0을 묘사할 뿐 그 수많은 키워드들을 모두 만족해야만 web2.0사이트가 된다는 것은 아니라는 뜻 입니다.

롱테일을 구현하기 위해서는 주류에 가려진 비주류를 드러낼 수 있어야 한다. 즉, 비주류의 findability를 제공하여야 한다.
그래서 성공적 웹2.0을 위해서는 findability를 제공하는 괜찮은 검색 기능이 필요한 것이다.
>롱테일을 구현하기 위해서 주류에 가려진 비주류를 드러낼 수 있어야 한다는 말에는 동의합니다. 하지만 비주류의 findability를 제공하는 것이 롱테일과 큰 연관이 있는지 잘 이해가 가지 않습니다.;; 혹시 롱테일법칙의 좋은 예로 많이 쓰이는 아마존의 도서 매출에 관한 말씀을 하시는 건지요.. 맞다면 그 findabilty는 web2.0이 제공해야할 것이라기 보다는 on-line이라는 웹의 특성이자 장점이 빚어낸 결과일뿐이라고 생각합니다. 이는 web2.0이전부터 전자상거래의 장점으로 꼽힌 부분이기도 하죠.. 아마존은 온라인이기때문에 도서전시 및 관리를 위한 비용이 들지 않았고, 이로서 주류인 20과 비주류인 80에 대해 똑같은 findability가 가능하였고 결국 그 80이 전 매출의 80을 넘는(사실 약간의 과장이라고 합니다만..) 롱테일 현상이 일어났다는 것으로 알고 있습니다..
web2.0을 너무 상업적인 의미로만 결부시키시는건 아닌가 우려됩니다.


openmaru의 springnote 서비스는 웹2.0인가?  findability 가 약하다. 오픈마루에서 검색 관련 일을 진행하는 걸로 봐서, 강한 findability 가 구축될 것으로 기대된다.

>키링크님이 말씀하신데로 web2.0이 개방, 참여, 공유를 특징으로 한다면 springnote는 지극히 web2.0적인 사이트라는 것입니다.
- 개방 : 서비스 구축과 함께 openAPI를 제공하고자 준비를 하였으며, 국내에서는 찾기 힘들 CRUD에 대한 OpenAPI를 제공하는 것은 지극히 개방적인 자세가 아닐까 생각합니다.
- 참여 : Springnote의 베타테스터를 경험했던 바로는 springnote서비스 자체가 국내 어떤 웹서비스보다도 사용자의 참여를 유도하며 그들의 피드백을 적극 수용한다는 것 입니다.  제공되는 서비스가 아닌 함께 만들어 가는 서비스로 말이죠.
- 공유 : Springnote의 주요 기능, 그리고 지향하고자 하는 바가 공유죠. 이미 문서에 대한 공동작성이 가능한 상태이고, 앞으로 팀스프링노트(이 또한 사용자의 참여에 의해 제안된 것이죠..)의 출시를 예고하고 있습니다.
springnote는 자신이 작성한 컨텐츠에 한해서(앞으로 통합 검색 지원 여부는 잘 모르겠습니다만...) fulltext기능을 제공 하기때문에 제가 작성한 컨텐츠에 대한 findability는 상당히 만족하는 편입니다. 다른 사용자들과의 컨텐츠 공유도 할수 있다면 좋겠죠. 어쩌면 Springnote가 앞으로 꼭 해야할 일중에 하나가 이것이 아닐까도 생각됩니다. 저도 그 부분엔 큰 기대를 걸고 있습니다^^

저의 생각은 이렇습니다.
Springnote나 myid가 여러가지 면에서 아직 보완해한다는 점에서 저 역시 공감합니다.
그래야만 하구요. 하지만 Tim O'reilly가 말한 web2.0의 정의 중에 "sw릴리즈 주기의 종말"이란 말도 있듯이 web2.0은 '완성된' 상태의 서비스가 아닌 불완전한 상태에서 지속적인 사용자의 '참여'로 점점 완전해지지만, 한편으로는 끊임없는 사용자의 요구, 환경의 변화에 적응하기 위해 영원한 베타로 남는 서비스라는 것입니다.
web2.0사이트는 지금까지의 성공적인 web2.0사이트들의 특징을 모두 만족하는 사이트가 아닌 사용자에게 편리를 주기 위한 끊임 없는 서비스정신으로 귀결된다고 생각합니다. 모든것은 "사람이 편하게"를 지향하니까요...
Springnote를 제법 초창기부터 써오며 느낀 Springnote에서는 다른 서비스들과 달리 사람냄세가 난다.. 란 것은 저만 그런걸까요. 아, 전 Springnote 예찬론자는 아닙니다. ㅋㅋ

너무 두서 없이 써내려간건 아닌가 모르겠네요.
저는 기말기사 기간입니다.. 전 이만..-0- !!!!
Posted by

Springnote의 컨셉영상. 멋지다.
Posted by