2009-11-26 3 views
0

GWT를 사용하여 페이스 북 플랫폼 웹 앱을 만들고 App Engine에 호스팅하고 있습니다.

제공된 쿼리 문자열 매개 변수를 콜백 URL에 사용하는 유효성 검사 코드를 추가하고 있습니다. GWT를 사용하면 Window.Location.getParameterMap()을 호출하여 이러한 매개 변수를 가져올 수 있으며 반환 된 Map은 변경되지 않습니다.

하지만이 문제는 FB, GWT 또는 App Engine과는 아무런 관련이 없으며 Map 객체에 대한 내 오해에 더 가깝다고 생각합니다.

내 코드가 제공된 맵을 수정하려고 시도하지 않았지만 얻은 오류로 인해 내 코드가 변경 불가능한 맵을 수정하려고 시도하는 것 같습니다.

수정할 수없는지도를 수정하고 싶은 사람이 있습니까?

스택 추적을 제공 하겠지만 스택 추적을 통해 App Engine 로그에 표시 할 수있는 방법을 찾을 수 없습니다. 일체의 사전에

덕분에 :-)

/** 
* Validation Test 
* To generate the signature for these arguments: 
* 1. Remove the fb_sig key and value pair. 
* 2. Remove the "fb_sig_" prefix from all of the keys. 
* 3. Sort the array alphabetically by key. 
* 4. Concatenate all key/value pairs together in the format "k=v". 
* 5. Append your secret key. 
* 6. Take the md5 hash of the whole string. 
* @param fbQueryStringParams 
* @return String 
*/ 
public String test(Map<String,List<java.lang.String>> fbQueryStringParams) { 

    String appSecret = TinyFBClient.APP_SECRET; 
    String fbSig = fbQueryStringParams.get("fb_sig").get(0); 
    StringBuilder sb = new StringBuilder();  
    TreeMap<String,String> sortedMap = new TreeMap<String,String>(); 

    // Get a Set view of the Map of query string parameters. 
    Set<Map.Entry<String,List<java.lang.String>>> mapEntries = fbQueryStringParams.entrySet(); 

    // Iterate through the Set view, inserting into a SortedMap all Map.Entry's 
    // that do not have a Key value of "fb_sig". 
    Iterator<Map.Entry<String,List<java.lang.String>>> i = mapEntries.iterator(); 
    while(i.hasNext()) { 

     Map.Entry<String,List<java.lang.String>> mapEntry = i.next(); 

     if(!mapEntry.getKey().equals("fb_sig")) { // 1. Remove the fb_sig key and value pair. 

      sortedMap.put(mapEntry.getKey(),mapEntry.getValue().get(0)); // 3. Sort the array alphabetically by key. 

     } 

    } 

    // Get a Set view of the Map of alphabetically sorted Map.Entry objects. 
    Set<Map.Entry<String,String>> sortedMapEntries = sortedMap.entrySet(); 

    // Iterate through the Set view, appending the concatenated key's and value's 
    // to a StringBuilder object. 
    Iterator<Map.Entry<String,String>> ii = sortedMapEntries.iterator(); 
    while(ii.hasNext()) { 

     Map.Entry<String,String> mapEntry = ii.next(); 

     // 4. Concatenate all key/value pairs together in the format "k=v". 
     sb.append(mapEntry.getKey().replaceAll("fb_sig_","")); // 2. Remove the "fb_sig_" prefix from all of the keys. 
     sb.append("="); 
     sb.append(mapEntry.getValue()); 

    } 

    sb.append(appSecret); // 5. Append your secret key. 

    String md5 = DigestUtils.md5Hex(sb.toString()); // 6. Take the md5 hash of the whole string. 

    // Build and return an output String for display. 
    StringBuilder output = new StringBuilder(); 
    output.append("fbSig = "+fbSig); 
    output.append("<br/>"); 
    output.append("md5 = "+md5); 
    return output.toString(); 

} 
+1

또한 오류 메시지를 게시하고 불만을 제기하는 행을 표시하십시오. –

+0

은 괜찮아 보이지만 어떤 맵은 변경 불가능한 맵입니까? 메서드의 매개 변수는 무엇입니까? –

+0

죄송합니다,이 사이트를 처음 사용했기 때문에 귀하는 의견을 남기 셨습니다. 전체 오류 메시지와 줄은 완벽하지만 "java.util.Collections $ UnmodifiableMap"을 생성하는 Throwable.getMessage()를 제쳐두고 유용한 것을 얻으려고 애 쓰고 있습니다. 그게 전부에요. 또한 메서드에 대한 매개 변수는 수정할 수 없습니다. 난 항상 그것을 (문서에) 알았지 만 내 코드가 우연히지도를 수정하려고했는지 확실하지 않았습니다. 귀하의 의견에 감사드립니다 :-) – Darren

답변

2

복사는 HashMap의 Windows.Location.getParameterMap()와 그것을 작동합니다

그래서 당신이 새의 HashMap를 보내> (Windows.Location.getParameterMap()) 작동 RPC를 통해.

문제는 unmodifiableMap이 GWT에 대해 Serializable이 아니라는 점입니다. Serializable 마커를 가지고 있지만, GWT에서는 약간 다른 점이 있습니다. 대부분의 콜렉션 클래스는 커스텀 GWT 구현을 가지고 있으며, 일부는 100 % 호환되지 않는다.

+1

안녕 데이빗. 나는 당신에게 투표하고 싶습니다만 어떻게해야할지 모르겠습니다. – Darren

1

내가 어떤 변경 불가능한 컬렉션을 볼 수 없습니다 도움이됩니다.

코드가 복잡합니다. 내가 그것을 올바르게 이해한다면, 이것은 동등해야합니다. Map.Entry 객체를 사용하지 않고 TreeMap에는 필요에 맞는 편리한 생성자가 있습니다. 그리고 마지막으로, iterator에 대해 'forall'루프를 선호합니다.

public String test(Map<String, List<java.lang.String>> fbQueryStringParams) { 
    String appSecret = TinyFBClient.APP_SECRET; 
    String fbSig = fbQueryStringParams.get("fb_sig").get(0); 
    StringBuilder sb = new StringBuilder(); 
    TreeMap<String, List<String>> sortedMap = new TreeMap<String, List<String>>(fbQueryStringParams); 
    sortedMap.remove("fbSig"); // remove the unwanted entry 

    for (String key, sortedMap.keySet()) { 
     List<String> values = sortedMap.get(key); 
     String printableKey = key.replaceAll("fb_sig_", "")); 
     String value = "EMPTY LIST"; 

     if (!values.isEmpty()) { 
      // This could have been your problem, you always 
      // assume, all lists in the map are not empty 
      value = values.get(0); 
     } 

     sb.append(String.format("%s=%s", printableKey, value); 
    } 

    sb.append(appSecret); 
    String md5 = DigestUtils.md5Hex(sb.toString()); 

    // Build and return an output String for display. 
    StringBuilder output = new StringBuilder(); 
    output.append("fbSig = " + fbSig); 
    output.append("<br/>"); 
    output.append("md5 = " + md5); 
    return output.toString(); 
} 

리팩토링 동안

나는 하나 개의 가능한 버그를 발견 : 당신은 당신의 코드에서 정렬 된 맵을 만들 때, 당신은 가정, 맵의 모든 목록이 비어 있지. 따라서 첫 번째 빈 목록은 첫 번째 루프에서 NPE를 발생시킵니다.

+0

이 Andreas를 살펴 주셔서 감사합니다. 내 대신 C & P 코드를 사용하여 어떤 일이 발생하는지 확인하십시오. – Darren

+0

버그가있는 경우 나를 괴롭히지 마십시오. 리팩토링하는 동안 IDE가 없었습니다.) –

+0

IDE가 없으면 몇 가지 간단한 구문 버그 만 있습니다. 여전히 같은 오류가 발생합니다. 이 메서드는 비동기 GWT 클래스 내에 있고 원격 프로 시저 호출이 실패 할 때 (예외가 발생하여 예외가 발생 함) 예외가 잡히고이 Throwable의 메시지가 출력되기 때문에이 오류 만 볼 수 있습니다. 이러한 예외를 App Engine 로그에 표시하는 방법을 알아야한다고 생각합니다. 도움을 주셔서 감사합니다. – Darren

0

Do a System.out.println (fbQueryStringParams.getClass()); 메시지의 시작 부분에 (또는 로그를 남기거나 무엇이 필요한지 알 수 있어야합니다.)

이 인수가 시스템에서 사용자에게 전달되면 변경하지 않으려 고하므로 수정 불가능한 모음으로 래핑 될 가능성이 큽니다.

+0

이번 TofuBeer에 대해 생각해 주셔서 감사합니다. 제공되는 Map은 URL의 쿼리 문자열에있는 매개 변수를 나타내므로 변경 불가능하므로 이러한 매개 변수를 수정해서는 안됩니다. 두 가지 코딩 솔루션이 맵을 수정하지 않는다는 점은 분명합니다. – Darren

+0

유용한 로깅 기능을 사용하는 데 실제 문제가 있습니다. GAE 설명서 (http://code.google.com/appengine/docs/java/runtime.html#Logging, )에 따르면 "서블릿이 표준 출력 스트림 (System.out)에 쓰고 표준 오류 stream (System.err)은 App Engine에 캡처되어 응용 프로그램 로그에 기록됩니다. 표준 출력 스트림에 기록 된 라인은 "INFO"레벨에서 기록되고 표준 오류 스트림에 기록 된 라인은 "WARNING"레벨에서 기록됩니다 . " 하지만 내 시도는 아무것도 발생시키지 않습니다. 나는 이것을 GAE 포럼에 가져 가야 할 것이다. – Darren

+0

정말 고객 측 버그가 있다고 생각합니다. –

0

클라이언트 코드에서 Window.Location.getParameterMap을 수행하고 RPC 호출로 서버로 보내는 것이 올바르게 이해 되었습니까? 그 경우에는 ... 문제는 ParameterMap을 직렬화 할 수 있는가하는 것입니다. 실제로 모든 구현이 GWT에서 지원되는 것은 아닙니다. 따라서 서버 코드가 호출되지는 않지만 요청을 보내기 전에 충돌하는 것일 수 있습니다. GWT 컴파일 중 경고가 표시 되었습니까?

코드는 구현을 정리할 수 있지만 실제로 NPE를 가질 수 있지만 제공된 매개 변수 Map 또는 Map 값의 List를 수정하지는 않습니다. 문제는 아마도 다른 곳에서 발생했을 것입니다.

응용 프로그램을 호스트 모드 (또는 GWT 2.0에서 호출 할 때 개발 모드)로 실행하지 않는 이유는 무엇입니까?

데이비드

+0

이 데이비드에 시간을 보내 주셔서 감사합니다. GWT 소스 코드에 따르면 Window.Location.getParameterMap()은 java.util.HashMap을 반환하고 J2SE 문서에 따르면 Serializable 인터페이스를 구현합니다. – Darren

+0

호스팅 모드가 진행되는 한, 나는 당신이 의미하는 바를 잘 모르겠다. Eclipse 용 GAE/GWT 플러그인을 사용합니다. 이것을 사용하면 로컬에서 응용 프로그램을 실행할 수 있으며 다른 이유로 코드가 실패합니다. 주로 올바른 FB URL을 얻지 못하지만 전체 스택 추적을 얻습니다. http://code.google.com/webtoolkit/doc/1.6/FAQ_DebuggingAndCompiling.html에 나와있는 것처럼 호스트 된 모드를 의미하는 경우 blimey를 설정하면 솔직히 말해서 나는 대부분을 이해하지 못합니다. 그것의 :-( GAE 로그에 나타나는 예외 및 스택 추적을 얻는 방법이 있어야합니다 - 어쩌면 내가 먼저 시도해야합니까? – Darren

+0

코드를 실제로 살펴 보았습니다.HashMap를 구축하고 있지만, 결국에는 Collections.unmodifiableMap를 돌려줍니다. GAE/GWT 플러그인을 사용하면 호스팅 모드에서 실행하는 것이 실제로 매우 간단합니다. GWT 프로젝트에서 웹 응용 프로그램으로 실행을 수행하십시오. 호스트 된 모드로 실행하는 데는 시간을 투자해야합니다. 개발 속도가 빠르며 클라이언트 측 버그를 훨씬 쉽게 처리 할 수 ​​있기 때문입니다. 클라이언트에서 뭔가 충돌이 발생하면 RPC 호출을하지 않으면 서버에 로그 할 수 없습니다. 좋은 생각이 아닙니다. 서버는 HTTP에서 실행 : 호스트 모드에서 –