废话不说,真接上代码。
HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestProperty("Content-Length", "0");
但是这个代码在android平台上跑的时候,第二句是起了作用的。
为了找出原因,真接跟到源代码中看:
public void setRequestProperty(String key, String value) { if (connected) throw new IllegalStateException("Already connected"); if (key == null) throw new NullPointerException ("key is null"); if (isExternalMessageHeaderAllowed(key, value)) { requests.set(key, value); } }
private boolean isExternalMessageHeaderAllowed(String key, String value) { checkMessageHeader(key, value); if (!isRestrictedHeader(key, value)) { return true; } return false; }
private boolean isRestrictedHeader(String key, String value) { if (allowRestrictedHeaders) { return false; } key = key.toLowerCase(); if (restrictedHeaderSet.contains(key)) { /* * Exceptions to restricted headers: * * Allow "Connection: close". */ if (key.equals("connection") && value.equalsIgnoreCase("close")) { return false; } return true; } else if (key.startsWith("sec-")) { return true; } return false; }
由上面代码可以看出,一个属性能不能加到request中,由allowRestrictedHeaders和restrictedHeaderSet决定的。如果key在restrictedHeaderSet,而且allowRestrictedHeaders为false时,这个key的值是不能加到request中的。
继续来看restrictedHeaderSet和allowRestrictedHeaders是哪里来的。在静态初始化代码中发现allowRestrictedHeaders是由安全管理器的返回值决定的。
restrictedHeaderSet的内容是由restrictedHeaders数组决定的。
allowRestrictedHeaders = ((Boolean)java.security.AccessController.doPrivileged( new sun.security.action.GetBooleanAction( "sun.net.http.allowRestrictedHeaders"))).booleanValue(); if (!allowRestrictedHeaders) { restrictedHeaderSet = new HashSet<String>(restrictedHeaders.length); for (int i=0; i < restrictedHeaders.length; i++) { restrictedHeaderSet.add(restrictedHeaders[i].toLowerCase()); } } else { restrictedHeaderSet = null; }
数组的声明如下:
private static final Set<String> restrictedHeaderSet; private static final String[] restrictedHeaders = { /* Restricted by XMLHttpRequest2 */ //"Accept-Charset", //"Accept-Encoding", "Access-Control-Request-Headers", "Access-Control-Request-Method", "Connection", /* close is allowed */ "Content-Length", //"Cookie", //"Cookie2", "Content-Transfer-Encoding", //"Date", "Expect", "Host", "Keep-Alive", "Origin", // "Referer", // "TE", "Trailer", "Transfer-Encoding", "Upgrade", //"User-Agent", "Via" };
但这是为什么呢?又应该如何解决呢?
于是搜索了下。
找到下面两篇。
http://stackoverflow.com/questions/6056125/why-does-content-length-http-header-field-use-a-value-other-than-the-one-given-i/6056230#6056230
http://lxy2330.iteye.com/blog/1882836
大概原因就是出于安全考虑,这些字段尽量不要被改动。sun就做了这一套安全机制。
解决方法是在JVM启动时加入sun.net.http.allowRestrictedHeaders
属性为true。
按第二篇里的做法,是失败的。
试着的JVM启动参数里面加,但失败了。
于是我就直接在程序里面加了。如下面代码。然后就OK了。
System.setProperty("sun.net.http.allowRestrictedHeaders", "true");