2011-07-03 36 views
1

这里此代码是一个正常的Java应用程序不是一个Android应用程序,这是为了C2DM消息发送到设备与YOUR_REGISTRATION_STRING与AUTH_KEY开发商,问题在下面HttpURLConnection c = URL.openConnection(); c.setRequestProperty()不工作

描述
import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.InputStreamReader; 
import java.io.OutputStream; 
import java.net.HttpURLConnection; 
import java.net.URL; 
import java.net.URLEncoder; 

import javax.net.ssl.HostnameVerifier; 
import javax.net.ssl.HttpsURLConnection; 
import javax.net.ssl.SSLSession; 


public class C2DMSendMessage { 
    private final static String AUTH = "authentication"; 

    private static final String UPDATE_CLIENT_AUTH = "Update-Client-Auth"; 

    public static final String PARAM_REGISTRATION_ID = "registration_id"; 

    public static final String PARAM_DELAY_WHILE_IDLE = "delay_while_idle"; 

    public static final String PARAM_COLLAPSE_KEY = "collapse_key"; 

    private static final String UTF8 = "UTF-8"; 

    // Registration is currently hardcoded 
    private final static String YOUR_REGISTRATION_STRING = "APA91bGf8gkFMn_sBP_hosSAiqUmmLwOdIqVSQKbbqXv2WSADQ51gbixInAGUk1U_vDIcz7izVaq6tvu8KXGsiQ7BIKy_7f04id00SUms8h3YGxbsKd6Jjg"; 

    public static void main(String[] args) throws Exception { 
     HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { 

      @Override 
      public boolean verify(String arg0, SSLSession arg1) { 
       // TODO Auto-generated method stub 
       return true; 
      } 
     }); 
     String auth_key = "DQAAAA4BAADAb7BDi6KY9pj11ERiY0R1TaEynLK6AtSPxzzIeCih_VDyWLhEJCvmkXjh6gRAsGpLb0wtAGmWIK9CjsBMT3upjnZ86tRYnvfOknkN45ORk29AsR2he-JEo1Y4eVcUutoPnBbIX2kzoEeY2ULYXyOQix7oWSWb4CJS3XYrb7qcmQxMv3yiIAF8kO0Sav7-NspCSI3tV3lISrz_BWqSCVGHWxT6KZ_PZwjH7442CpMfZhOYxsgDanQod8EypHjHmNQK_txWwFeiFj66jsi90BpyPKvUX_ZUbOmSKVZP3gBcKrK9iSnJrSUpLuEN46NGRzl2uBg9I9V-wJuFBgG1aBXqA1oWFdkEewxwXapuVqR1-g"; 
     // Send a sync message to this Android device. 
     StringBuilder postDataBuilder = new StringBuilder(); 
     postDataBuilder.append(PARAM_REGISTRATION_ID).append("=") 
       .append(YOUR_REGISTRATION_STRING); 

     // if (delayWhileIdle) { 
     // postDataBuilder.append("&").append(PARAM_DELAY_WHILE_IDLE) 
     // .append("=1"); 
     // } 
     postDataBuilder.append("&").append(PARAM_COLLAPSE_KEY).append("=") 
       .append("0"); 

     postDataBuilder.append("&").append("data.payload").append("=") 
       .append(URLEncoder.encode("Lars war hier", UTF8)); 

     byte[] postData = postDataBuilder.toString().getBytes(UTF8); 

     // Hit the dm URL. 

     URL url = new URL("https://android.clients.google.com/c2dm/send"); 

     HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 
     conn.setDoOutput(true); 
     conn.setUseCaches(false); 
     conn.setRequestMethod("POST"); 
     conn.setRequestProperty("Content-Type", 
       "application/x-www-form-urlencoded;charset=UTF-8"); 
     conn.setRequestProperty("Content-Length", 
       Integer.toString(postData.length)); 
     conn.setRequestProperty("Authorization", "GoogleLogin auth=" 
       + auth_key); 
     System.out.println(conn.getRequestProperties()); 
     OutputStream out = conn.getOutputStream(); 
     out.write(postData); 
     out.close(); 

     int responseCode = conn.getResponseCode(); 

     System.out.println(String.valueOf(responseCode)); 
     // Validate the response code 

     if (responseCode == 401 || responseCode == 403) { 
      // The token is too old - return false to retry later, will 
      // fetch the token 
      // from DB. This happens if the password is changed or token 
      // expires. Either admin 
      // is updating the token, or Update-Client-Auth was received by 
      // another server, 
      // and next retry will get the good one from database. 
      System.out.println("Unauthorized - need token"); 
     } 

     // Check for updated token header 
     String updatedAuthToken = conn.getHeaderField(UPDATE_CLIENT_AUTH); 
     if (updatedAuthToken != null && !auth_key.equals(updatedAuthToken)) { 
      System.out.println("Got updated auth token from datamessaging servers: " 
          + updatedAuthToken); 
     } 

     String responseLine = new BufferedReader(new InputStreamReader(
       conn.getInputStream())).readLine(); 

     // NOTE: You *MUST* use exponential backoff if you receive a 503 
     // response code. 
     // Since App Engine's task queue mechanism automatically does this 
     // for tasks that 
     // return non-success error codes, this is not explicitly 
     // implemented here. 
     // If we weren't using App Engine, we'd need to manually implement 
     // this. 
     if (responseLine == null || responseLine.equals("")) { 
      System.out.println("Got " + responseCode 
        + " response from Google AC2DM endpoint."); 
      throw new IOException(
        "Got empty response from Google AC2DM endpoint."); 
     } 

     String[] responseParts = responseLine.split("=", 2); 
     if (responseParts.length != 2) { 
      System.out.println("Invalid message from google: " + responseCode 
        + " " + responseLine); 
      throw new IOException("Invalid response from Google " 
        + responseCode + " " + responseLine); 
     } 

     if (responseParts[0].equals("id")) { 
      System.out.println("Successfully sent data message to device: " 
        + responseLine); 
     } 

     if (responseParts[0].equals("Error")) { 
      String err = responseParts[1]; 
      System.out.println("Got error response from Google datamessaging endpoint: " 
          + err); 
      // No retry. 
      throw new IOException(err); 
     } 
    } 
} 
在上述我试图发送C2DM消息的代码

但它是不相关的

URL url = new URL("https://android.clients.google.com/c2dm/send"); 

HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 
conn.setDoOutput(true); 
conn.setUseCaches(false); 
conn.setRequestMethod("POST"); 
conn.setRequestProperty("Content-Type","application/x-www-form-urlencoded;charset=UTF-8"); 
conn.setRequestProperty("Content-Length",Integer.toString(postData.length)); 
conn.setRequestProperty("Authorization", "GoogleLogin auth="+ auth_key); 
System.out.println(conn.getRequestProperties()); 

在我已经重复我试图设置请求属性其中3但只有1没有到达的部分hashmap in conn 这是输出:

{的Content-Type = [应用/ X WWW的窗体-urlencoded;字符集= UTF-8]}

我不理解代码如何可以运行,如果它是在它自己的只是那些线 ,而不是提前上班的一个更大的代码部分

我也addRequestProperty试过

感谢

回答

5

Instea在request属性中设置Content-Length的d,使用setFixedLengthStreamingMode(postData.length);

根据该源为HttpUrlConnection,内容长度是一个“限制头”:

146  /* 
147  * Restrict setting of request headers through the public api 
148  * consistent with JavaScript XMLHttpRequest2 with a few 
149  * exceptions. Disallowed headers are silently ignored for 
150  * backwards compatibility reasons rather than throwing a 
151  * SecurityException. For example, some applets set the 
152  * Host header since old JREs did not implement HTTP 1.1. 
153  * Additionally, any header starting with Sec- is 
154  * disallowed. 
155  * 
156  * The following headers are allowed for historical reasons: 
157  * 
158  * Accept-Charset, Accept-Encoding, Cookie, Cookie2, Date, 
159  * Referer, TE, User-Agent, headers beginning with Proxy-. 
160  * 
161  * The following headers are allowed in a limited form: 
162  * 
163  * Connection: close 
164  * 
165  * See http://www.w3.org/TR/XMLHttpRequest2. 
166  */ 
167  private static final boolean allowRestrictedHeaders; 
168  private static final Set<String> restrictedHeaderSet; 
169  private static final String[] restrictedHeaders = { 
170   /* Restricted by XMLHttpRequest2 */ 
171   //"Accept-Charset", 
172   //"Accept-Encoding", 
173   "Access-Control-Request-Headers", 
174   "Access-Control-Request-Method", 
175   "Connection", /* close is allowed */ 
176   "Content-Length", 
177   //"Cookie", 
178   //"Cookie2", 
179   "Content-Transfer-Encoding", 
180   //"Date", 
181   //"Expect", 
182   "Host", 
183   "Keep-Alive", 
184   "Origin", 
185   // "Referer", 
186   // "TE", 
187   "Trailer", 
188   "Transfer-Encoding", 
189   "Upgrade", 
190   //"User-Agent", 
191   "Via" 
192  }; 

所以,设定内容长度将被忽略。

授权是从返回出于安全目的,阻止:

249  // the following http request headers should NOT have their values 
250  // returned for security reasons. 
251  private static final String[] EXCLUDE_HEADERS = { 
252    "Proxy-Authorization", 
253    "Authorization" 
254  }; 
255 
256  // also exclude system cookies when any might be set 
257  private static final String[] EXCLUDE_HEADERS2= { 
258    "Proxy-Authorization", 
259    "Authorization", 
260    "Cookie", 
261    "Cookie2" 
262  }; 

所以,即使你设定的授权头,你不会得到它回来时,你查询的头。

+0

我用conn.setFixedLengthStreamingMode(postdata.length)替换了内容长度行;仍然输出的是请求属性:{Content-Type = [application/x-www-form-urlencoded; charset = UTF-8]} 授权从未输入请求属性:/,注意我也试过了设置的长度为 –

+0

,如你所见n我的代码我正在使用 import java.net.HttpURLConnection;不是太阳httpurl,日食只是不会使用太阳一个 –

+0

该HttpURLConnection是不允许你设置内容的长度,并不会报告给你。授权被明确排除在属性图中返回。我已更新并扩展了我的原始答案,以包含更多评论。 – g051051

1

内容长度自动设置。你不能直接设置它。但是,您可以在设置固定长度流模式时传递正确的长度。

+0

方法setFixedLengthStreamingMode用于此目的。从JavaDoc:“此方法用于在没有内部缓冲的情况下启用HTTP请求主体的流式传输,当内容长度事先已知时”。 – g051051

+0

我删除它,仍然授权是从来没有真正进入请求属性 –

+0

再一次,你将无法读回它...在Java运行时的实现限制了这个头出于安全原因。使用协议嗅探器检查您的流量,如Fiddler。您应该在流量中看到授权标头。 – g051051

相关问题