编写的类SourceCode用于发送网络请求,主要用HttpUrlConnection实现。同一段代码,在电脑上能运行,移植到安卓应用却运行失败。在电脑上运行响应200正常,在手机应用运行时通过打印得知响应码为405,但没有任何错误。 开始时我以为是应用网络权限问题、安卓网络安全机制问题,甚至是url写错了,后来都排除了。 405错误一般是请求方法错误,服务端只接收post请求而我们发送get请求,或相反。我发送的是get请求,打开的网址是网站首页,这个页面是不可能用post请求才能打开的。分析代码,又没发现什么问题,发送的确实是get请求,con.setRequestMethod(“GET”)。真让人摸不着头脑。我之前也是做过安卓的联网应用的,没出现这种问题。 这时,网络上的一句话引起了我的注意,“setDoOutput(true)可能导致请求变为POST请求”。我对于打开的url连接先进行了统一设置,其中正包含“setDoOutput(true)”。在发送get请求的函数中设置setDoOutput(false),果然成功了。 通过打印,得知在手机上url.openConnection()得到的连接的实现类是com.android.okhttp.internal.huc.HttpURLConnectionImpl/HttpsURLConnectionImpl,而电脑上的实现类是原装的sun.net.www.protocol.http.HttpURLConnection/HttpsURLConnectionImpl
结论:对于HttpUrlConnection,
即使设置了setRequestMethod(“GET”),在setDoOutput(true)的情况下也可能会被认为是POST请求
,并且该情况与两个set方法的先后顺序无关。所以 在用HttpURLConnection发送GET请求时,一定要设置setDoOutput(false)
import com.report.auto.multi.AutoRetry;
import com.report.auto.multi.WatchedThread;
import javax.net.ssl.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class SourceCode {
StringBuffer sourceCode = null;
public SourceCode() {
init();
}
private void getHeaders(HttpURLConnection coon){
Map<String, List<String>> headerFields = coon.getHeaderFields();
Set<String> strings = headerFields.keySet();
for(String key:strings){
System.out.println(key+"="+headerFields.get(key));
}
}
public StringBuffer getSourceCodeInGet(String url,boolean canJump) {
try {
HttpURLConnection httpUrlCon;
httpUrlCon = getConnection(url);
httpUrlCon.setRequestMethod("GET");
httpUrlCon.setDoOutput(false);
handleHeader(httpUrlCon);
int responseCode=httpUrlCon.getResponseCode();
switch (responseCode){
case 302: case 301:
if(!canJump)return null;
System.out.println("跳转");
String newUrl=httpUrlCon.getHeaderField("Location");
if(newUrl==null)newUrl=httpUrlCon.getHeaderField("location");
newUrl=getFullUrl(url,newUrl);
if(newUrl==null)return null;
return getSourceCodeInGet(newUrl,canJump);
case 404: case 403:return null;
case 200:
return getContent(httpUrlCon);
}
} catch (IOException e) {
System.err.println(url);
e.printStackTrace();
}
return null;
}
public String getFullUrl(String sourceUrl,String path){
if(path.startsWith("http://")||path.startsWith("https://"))return path;
try {
int protocolIndex = sourceUrl.indexOf("//")+2;
int siteIndex=sourceUrl.indexOf("/",protocolIndex);
String site;
if(siteIndex!=-1)site=sourceUrl.substring(0,siteIndex);
else site=sourceUrl+"/";
return site+path;
}catch (Exception e){}
return null;
}
public StringBuffer getSourceCodeInPost(String url,String data){
StringBuffer sourceCode = new StringBuffer();
HttpURLConnection httpUrlCon;
httpUrlCon = getConnection(url);
PrintWriter printWriter = null;
try {
httpUrlCon.setRequestMethod("POST");
httpUrlCon.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
printWriter = new PrintWriter(httpUrlCon.getOutputStream());
printWriter.write(data);
printWriter.flush();
printWriter.close();
handleHeader(httpUrlCon);
int responseCode=httpUrlCon.getResponseCode();
switch (responseCode){
case 302: case 301:
String newUrl=httpUrlCon.getHeaderField("location");
if(newUrl==null)newUrl=httpUrlCon.getHeaderField("Location");
getSourceCodeInGet(newUrl,true);
break;
case 404: case 403:return null;
case 200: return getContent(httpUrlCon);
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
Charset charset=StandardCharsets.UTF_8;
public StringBuffer getContent(HttpURLConnection connection) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), charset));
String line;
StringBuffer sourceCode=new StringBuffer();
while ((line = reader.readLine()) != null) {
sourceCode.append(line).append("\n");
}
reader.close();
this.sourceCode=sourceCode;
return sourceCode;
}
private void handleHeader(HttpURLConnection connection){
addCookie(connection.getHeaderField("Set-Cookie"));
}
int userAgent=2;
static String[] userAgents={"Chrome/71.0.3578.98 Safari/537.36",
"Mozilla/4.0 compatible; MSIE 5.0;Windows NT;",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36"};
public HttpURLConnection getConnection(String urlStr) {
URL url;
HttpURLConnection conn = null;
try {
url = new URL(urlStr);
conn = (HttpURLConnection) url.openConnection();
conn.setRequestProperty("user-agent",userAgents[userAgent]);
conn.setRequestProperty("accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8");
conn.setRequestProperty("accept-language", "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3");
conn.setRequestProperty("cache-control","max-age=0");
conn.setRequestProperty("connection", "keep-alive");
conn.setRequestProperty("cookie",getCookieString());
conn.setRequestProperty("upgrade-insecure-requests", "1");
conn.setRequestMethod("GET");
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setInstanceFollowRedirects(false);
conn.setReadTimeout(60*1000);
conn.setConnectTimeout(60*1000);
if(conn instanceof HttpsURLConnection){
((HttpsURLConnection)conn).setSSLSocketFactory(getSSLFactory());
}
} catch (IOException e) {
e.printStackTrace();
}
setRequestHeader(conn,initHeader);
System.out.println(conn.getClass());
return conn;
}
String initHeader=null;
public void setRequestHeader(HttpURLConnection connection,String text){
if(text==null)return;
String[] lines = text.split("\n");
for(String line:lines){
if(line.startsWith(":"))line=line.substring(1);
String[] split = line.split(":");
if(split.length!=2)continue;
connection.setRequestProperty(split[0].trim(),split[1].trim());
}
}
public void setInitHeader(String initHeader) {
this.initHeader = initHeader;
}
Map<String,String>cookieMap=new HashMap<>();
public void addCookie(String set_cookie){
if(set_cookie==null)return;
String[] cookies=set_cookie.split(";");
for(String c:cookies){
if(c.contains("=")) {
String[] split = c.split("=");
if(!split[0].trim().equals("path"))
cookieMap.put(split[0].trim(),split[1].trim());
}
}
}
public SSLSocketFactory getSSLFactory(){
try {
SSLContext sslContext=SSLContext.getInstance("SSL");
TrustManager[] tm={new X509TrustManager(){
@Override
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}};
sslContext.init(null, tm, new java.security.SecureRandom());
SSLSocketFactory ssf=sslContext.getSocketFactory();
return ssf;
}catch ( NoSuchAlgorithmException | KeyManagementException e){
}
return null;
}
public String getCookieString(){
StringBuilder cookie= new StringBuilder();
for(String key: cookieMap.keySet()){
cookie.append(key).append("=").append(cookieMap.get(key)).append(";");
}
return cookie.toString();
}
private void init() {
}
public void clearCookies(){
cookieMap.clear();
}
public String getHtmlWithAutoRetry(String url,int time){
AutoRetry<String> autoRetry=new AutoRetry<String>() {
@Override
public WatchedThread<String> getNewThread() {
return new WatchedThread<String>() {
@Override
public void callBack(String result) {
}
@Override
public String runTask() {
StringBuffer sourceCodeInGet = getSourceCodeInGet(url,true);
if(sourceCodeInGet==null)return null;
return sourceCodeInGet.toString();
}
};
}
};
autoRetry.setRetryTimes(time);
return autoRetry.runForUsableResult();
}
int retryTime=3;
public String getHtmlWithAutoRetry(String url){
return getHtmlWithAutoRetry(url,retryTime);
}
public void setRetryTime(int retryTime) {
this.retryTime = retryTime;
}
public static void main(String[] args) {
System.out.println(new SourceCode().getSourceCodeInGet("http://www.baidu.com", true));
}
package com.report.auto.multi;
public abstract class AutoRetry<T>{
int retryTimes=3;
boolean retryOnNullResult=true;
int retrySpace=5000;
protected WatchedThread<T> thread;
public T runForUsableResult(){
boolean shouldRetry=false;
int time=0;
do {
thread=getNewThread();
if(thread==null)return null;
thread.start();
boolean b=thread.waitUntilOK();
time++;
shouldRetry=(!b||(retryOnNullResult&&thread.getResult()==null))&&time<retryTimes;
if(shouldRetry)sleep(retrySpace);
}while (shouldRetry);
return thread.getResult();
}
public abstract WatchedThread<T> getNewThread();
private void sleep(int time){
try {
Thread.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public int getRetryTimes() {
return retryTimes;
}
public void setRetryTimes(int retryTimes) {
this.retryTimes = retryTimes;
}
public boolean isRetryOnNullResult() {
return retryOnNullResult;
}
public void setRetryOnNullResult(boolean retryOnNullResult) {
this.retryOnNullResult = retryOnNullResult;
}
public int getRetrySpace() {
return retrySpace;
}
public void setRetrySpace(int retrySpace) {
this.retrySpace = retrySpace;
}
}
package com.report.auto.multi;
public abstract class WatchedThread<T> extends Thread{
volatile boolean isOK=false;
int timeOut=60000;
long startTime;
volatile boolean isGivenUp=false;
T result;
public WatchedThread(){
}
public boolean isOK() {
return isOK;
}
@Override
public synchronized void start() {
super.start();
startTime=System.currentTimeMillis();
}
public boolean isTimeOut(){
return System.currentTimeMillis()-startTime>=timeOut;
}
public abstract T runTask();
public abstract void callBack(T result);
@Override
public void run(){
T t = runTask();
result=t;
if(!isGivenUp) {
callBack(t);
}
isOK=true;
}
private void sleep(int time){
try {
Thread.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public boolean waitUntilOK(){
while(!isOK){
sleep(10);
if(isTimeOut()){
isGivenUp=true;
this.interrupt();
return false;
}
}
return true;
}
public T getResult() {
return result;
}
}
.
|