메뉴 건너뛰기

app

[GAS] 구글 앱스 계정에서 JSONP 사용

lispro062016.01.11 01:38조회 수 1987댓글 0

    • 글자 크기

일단, JSON과 JSONP 의 차이점을 알자.


A라는 도메인에서 B서버의 데이터를 엑세스할 때, 크로스 도메인 문제 CORS(Cross-origin resource sharing)로 지원해주기 위해 JSON 에 P(adding)를 붙였다. json은 javascript object notation 이며, 이녀석에 익숙해지니 with padding (추운가 보다, 패딩을 입고 나타났다!!!) 으로 도메인을 넘나드는 근육질이 되었다.


정확한 설명은 wiki에서, jsonp, cors 를 찾아보면 되고, 이를 google apps 에서 해결한 사례를 소개한다.(2일 정도 걸림)


1) 구글 앱스는 무료 도메인에서, 문서나 스크립트, 기타 자원들을 도메인간 사용자에게만 오픈하는 폐쇄적인 정책이 있다.

2) 유료 도메인에서는 기존 gmail 계정 처럼 모두 에게 오픈 가능하고, 도메인간 사용자에게 오픈도 가능하다.


1)의 문제로 구글 앱스 무료 계정에서 스크립트를 웹앱 형태로 배포하여 사용하려고 하면 크로스 도메인 문제가 발생한다. json 방식으로 ajax 요청이 불가능하며, 동일 도메인 계정으로 로그인한 상태에서 jsonp를 사용하여 ajax 요청을 해야 한다.


"보안적으로 상당히 높은 수준이다" -> 구현이 어렵다는 뜻


웹앱 방식으로 사용해 기존에 돌아가는 웹 애플리케이션의 데이터를 쉽게 스프레드시트를 전달이 가능했는데, http://nubiz.tistory.com/538 구글 앱스 무료 도메인에서는 다른 방법이 필요해진 것이다.


http://excelramblings.blogspot.kr/2014/01/google-apps-script-content-service.html


위 사이트에서는 jsonp 로 ajax cors 가 가능한 방법을 설명한다. POST는 jQuery changes the POST jSONP to a GET 이라고 되어있는데, 일단 안된다.


CORS, JSONP 는 GET only 로 생각된다. 해결 방법 있으면 도입해야겠다.


일단, GET 방식으로 구현한 소스를 공개한다. 이 소스는 http://nubiz.tistory.com/538, http://excelramblings.blogspot.kr/2014/01/google-apps-script-content-service.html 를 조합하고, 여러 테스트를 거쳤다.


[구글 앱스 스크립트 - 게시에서 배포 후 사용한다]


//  1. Enter sheet name where data is to be written below

        var SHEET_NAME = "Sheet1";

         

//  2. Run > setup

//

//  3. Publish > Deploy as web app

//    - enter Project Version name and click 'Save New Version'

//    - set security level and enable service (most likely execute as 'me' and access 'anyone, even anonymously)

//

//  4. Copy the 'Current web app URL' and post this in your form/script action

//

//  5. Insert column names on your destination sheet matching the parameter names of the data you are passing in (exactly matching case)

 

var SCRIPT_PROP = PropertiesService.getScriptProperties(); // new property service

 

function doGet(e){

  return makeContent(handleResponse(e,"GET"));

}

 

function doPost(e){

  return makeContent(handleResponse(e,"POST"));

}

function makeContent(content) {

  return ContentService.createTextOutput(content.content)

              .setMimeType(content.mime);

}

function handleResponse(e,type) {

  // shortly after my original solution Google announced the LockService[1]

  // this prevents concurrent access overwritting data

  // [1] http://googleappsdeveloper.blogspot.co.uk/2011/10/concurrency-and-google-apps-script.html

  // we want a public lock, one that locks for all invocations

  var lock = LockService.getPublicLock();

  lock.waitLock(30000);  // wait 30 seconds before conceding defeat.

  

  try {

    // next set where we write the data - you could write to multiple/alternate destinations

    var doc = SpreadsheetApp.openById(SCRIPT_PROP.getProperty("key"));

    var sheet = doc.getSheetByName(SHEET_NAME);

    // we'll assume header is in row 1 but you can override with header_row in GET/POST data

    var headRow = e.parameter.header_row || 1;

    var headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0];

    var nextRow = sheet.getLastRow()+1; // get next row

    var row = [];

    // loop through the header columns

    for (i in headers){

      if (headers[i] == "Timestamp"){ // special case if you include a 'Timestamp' column

        row.push(new Date());

      } else { // else use header name to get data

        row.push(e.parameter[headers[i]]);

      }

    }

    // more efficient to set values as [][] array than individually

    sheet.getRange(nextRow, 1, 1, row.length).setValues([row]);

    var prot = {result:"success",row:nextRow};

    var s  = JSON.stringify({type:type,params:e,prot:prot});

    return {mime:ContentService.MimeType.JAVASCRIPT,content:e.parameter.callback + "(" + s + ");" };

  } catch(e){

    var prot = {result:"error",error:e};

    var s  = JSON.stringify({type:type,params:e,prot:prot});

    return {mime:ContentService.MimeType.JAVASCRIPT,content:e.parameter.callback + "(" + s + ");" };

  } finally { //release lock

    lock.releaseLock();

  }

}

 

function setup() {

    var doc = SpreadsheetApp.getActiveSpreadsheet();

    SCRIPT_PROP.setProperty("key", doc.getId());

}


[자바스크립트]

var u = ""; // 상기 구글 앱스 스크립트에서 배포된 웹앱 경로


// 아래와 같은 형태로 정의된 함수를 호출하여 스프레드시트에 전달되는 값과 리턴 값을 확인한다.


ajaxStuff("GET",u,{"컬럼명1":"컬럼데이터1", "컬럼명2":"컬럼데이터2" },true);


function ajaxStuff(method,url,postData,p) {

var p = (p ? true: false);

url += "?method="+method + "&p=" +p;

dataType = p ? "jsonp" : "json";

var elem = $('#'+method+p);

if (p) url += "&callback=?";

$.ajax({

 type:method,

 url: url,

 data: postData,

 dataType: dataType,

 callback : "list",


 success: function(data){

         $(data.prot).each(function(key, val){

              console.log(val.result); 

              console.log(val.row); 

         });

 },

  error : function(){

         $(data.prot).each(function(key, val){

              console.log(val.result); 

              console.log(val.error); 

         });

 }

});

}


[팁]

var s  = JSON.stringify({type:type,params:e,prot:prot});

리턴된 json에는 e가 들어있어서, 리퀘스트 파라미터가 모두 들어있다. 필요없으면, params:e를 구글 앱스 스크립트에서 삭제한다.


리턴된 json을 활용하고자 한다면, 아래와 같이 변형 가능하다.


   success : function(data) {
         $(data.prot).each(function(key, val){
              alert(val.result); 
         });
   },

lispro06 (비회원)
    • 글자 크기
[WIN] 날짜 표시 방법에 따른 년월일 추출 (by lispro06) [GAS] 설문지가 여러개 있는 시트이름 확인 및 동적 폼 셀렉트 리스트 (by lispro06)

댓글 달기

lispro06
2015.11.20 조회 1475
lispro06
2015.05.15 조회 1469
lispro06
2015.05.15 조회 1456
lispro06
2015.05.15 조회 2318
이전 1 2 3 4 5 6 7 8 9 10... 14다음
첨부 (0)
위로