有个需求,要用http请求控制和获取一个设备,我使用浏览器直接发送请求和使用ajax都是正常的,但是使用java代码发送http请求居然报错 java.io.IOException: Invalid Http response 我的代码是用的URLConnection
String result = "";
BufferedReader in = null;
try {
URL realUrl = new URL(url);
// 打开和URL之间的连接
URLConnection connection = realUrl.openConnection();
// 设置通用的请求属性
connection.setRequestProperty("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3");
connection.setRequestProperty("Accept-Encoding","gzip, deflate");
connection.setRequestProperty("Accept-Language","zh-CN,zh;q=0.9");
connection.setRequestProperty("Cache-Control","max-age=0");
connection.setRequestProperty("Connection","keep-alive");
connection.setRequestProperty("User-Agent","Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36");
connection.setRequestProperty("Content-Type","text/plain");
// 建立实际的连接
connection.connect();
// 定义 BufferedReader输入流来读取URL的响应
InputStream inputStream=connection.getInputStream();
in = new BufferedReader(new InputStreamReader(inputStream, "utf-8"));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
System.out.println("发送GET请求出现异常!" + e);
e.printStackTrace();
} finally {// 使用finally块来关闭输入流
try {
if (in != null) {
in.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
报错就在getInputStream那里,用了很多网上的方法,说是重复连接什么的,都没好使,后来我使用抓包工具 wireshark 发现这个设备给的返回值有问题
可以看到,其他的请求返回的都是符合http格式的,这个玩意返回的直接就是数据,不符合格式.
后来,我点到源码里取找到底哪里报的这个错,发现在 sun.net.www.protocol.http.HttpURLConnection 这个类是URLConnection的实现类,我去debug他的getInputStream方法,最后走的是getInputStream0方法,而抛出异常也在这个方法里
就是如果这个 getResponseCode 返回值为-1 那么就抛出这个异常,我想了一下,那么如果我继承这个类然后重写一下这个方法,是不是就好了
public class MyHttpURLConnection extends HttpURLConnection {
protected MyHttpURLConnection(URL url, Handler handler) throws IOException {
super(url, handler);
}
public MyHttpURLConnection(URL url, String s, int i) throws IOException {
super(url, s, i);
}
public MyHttpURLConnection(URL url, Proxy proxy) throws IOException {
super(url, proxy);
}
protected MyHttpURLConnection(URL url, Proxy proxy, Handler handler) throws IOException {
super(url, proxy, handler);
}
public int getResponseCode() throws IOException {
System.out.println("200 ok");
return 200;
}
}
然后,强制它返回200(这个因为我只在这一个地方用,而且也没细看其他的实现,只想获取他的输入流然后解析,所以就这么写了,大家如果有更好的方法可以评论一下),我找如何将我自己的类替换这个父类,然后去找URL的openConnection方法,发现是一个Handler类去生成的,这个handler是构造可以传入的,ok,继承,重写一条龙
public class MyHandler extends Handler {
protected URLConnection openConnection(URL var1, Proxy var2) throws IOException {
//这里返回自己的
return new MyHttpURLConnection(var1, var2, this);
}
}
继承的是sun.net.www.protocol.http.Handler,不要弄错
然后修改一开始的那个URL的new的方法就行了
//URL realUrl = new URL(url);
URL realUrl = new URL(null,url,new MyHandler());
然后测试执行打印 sendGet__result:<?xml version="1.0" encoding="utf-8"?>… ,ok了!
这个解决的方法可能比较粗暴,如果大家有更好的方法,欢迎讨论