1.这个错误在网上看到别人有好多说的,但是要不就是说,获取服务器响应的时候没有,关闭流
之类的,后来发现我自己的情况,都不是这样的.
说一下我这边的情况,因为请求的时候,后台我是用springcloud中验证是否可以请求,但是我这里不是验证的token,而是我自己设计的一种验证方式:
public static String getUserInfo(String phone,String yysId) {
// 请求url
String server_ip = GetConfigValue.getConfigProperties("server_ip");
//String url = "http://172.19.128.53:8080/api/mdd/user/getUserInfo";
String url = server_ip "/api/mdd/user/getUserInfo";
try {
Map<String, Object> map = new HashMap<>();
map.put("cell",phone);
map.put("managerId",yysId);
String param = GsonUtils.toJson(map);
String result = HttpUtil.post(url, "application/json", param);
//String result = HttpUtil.post(url, "application/x-www-form-urlencoded", param);
System.out.println(result);
return result;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
上面是我发送的一个请求:
package com.baidu.idl.face.main.utils;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* http 工具类
*/
public class HttpUtil {
public static String baidupost(String requestUrl, String accessToken, String params)
throws Exception {
String contentType = "application/x-www-form-urlencoded";
return HttpUtil.post(requestUrl, accessToken, contentType, params);
}
//1.自动门店登录用
public static String post(String requestUrl, String params)
throws Exception {
String contentType = "application/x-www-form-urlencoded";
return HttpUtil.post(requestUrl, contentType, params);
}
public static String baidupost(String requestUrl, String accessToken, String contentType, String params)
throws Exception {
String encoding = "UTF-8";
if (requestUrl.contains("nlp")) {
encoding = "GBK";
}
return HttpUtil.baidupost(requestUrl, accessToken, contentType, params, encoding);
}
public static String post(String requestUrl, String contentType, String params)
throws Exception {
String encoding = "UTF-8";
if (requestUrl.contains("nlp")) {
encoding = "GBK";
}
return HttpUtil.post(requestUrl, contentType, params, encoding);
}
public static String baidupost(String requestUrl, String accessToken, String contentType, String params, String encoding)
throws Exception {
String url = requestUrl "?access_token=" accessToken;
return HttpUtil.postGeneralUrl(url, contentType, params, encoding);
}
public static String post(String requestUrl, String contentType, String params, String encoding)
throws Exception {
String url = requestUrl;
return HttpUtil.postGeneralUrl(url, contentType, params, encoding);
}
//1.--->这里报错的地方是在
public static synchronized String postGeneralUrl(String generalUrl, String contentType, String params, String encoding)
throws Exception {
URL url = new URL(generalUrl);
// 打开和URL之间的连接
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
// 设置通用的请求属性
connection.setRequestProperty("Content-Type", contentType);
connection.setRequestProperty("Connection", "Keep-Alive");
connection.setUseCaches(false);
connection.setDoOutput(true);
connection.setDoInput(true);
//添加请求头部 appkey appsecret
String APPKEY = "xxxxx";//自己定义的
String APPDATE ="";
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
APPDATE = dateFormat.format(new Date());
String SECRETBEFORE = APPKEY YdCommonUtils.reverseString(APPDATE) APPKEY.toUpperCase();
String APPSECRET = YdCommonUtils.getMD5Str(SECRETBEFORE);
connection.setRequestProperty("appkey",APPKEY);
connection.setRequestProperty("appdate",APPDATE);
connection.setRequestProperty("appsecret",APPSECRET);
// 得到请求的输出流对象
DataOutputStream out = new DataOutputStream(connection.getOutputStream());
out.write(params.getBytes(encoding));
out.flush();
out.close();
// 建立实际的连接
connection.connect();
// 获取所有响应头字段
Map<String, List<String>> headers = connection.getHeaderFields();
// 遍历所有的响应头字段
for (String key : headers.keySet()) {
System.err.println(key "--->" headers.get(key));
}
// 定义 BufferedReader输入流来读取URL的响应
BufferedReader in = null;
in = new BufferedReader(
new InputStreamReader(connection.getInputStream(), encoding));
String result = "";
String getLine;
while ((getLine = in.readLine()) != null) {
result = getLine;
}
in.close();
System.err.println("result:" result);
return result;
}
}
可以看到请求是经过上面的这个工具类发出去的,但是,报错就在
// 定义 BufferedReader输入流来读取URL的响应
BufferedReader in = null;
in = new BufferedReader(
new InputStreamReader(connection.getInputStream(), encoding));
String result = "";
String getLine;
while ((getLine = in.readLine()) != null) {
result = getLine;
}
上面代码的这个部分,其实就是,连接是已经连接上了,主要是读取,服务器返回数据的时候,报错了
报的错误就是:java.io.FileNotFoundException: http://172.19.128.53:8080/ 这样的情况
什么原因呢?
我们再去看看我服务器验证部分的代码,对于所有的接口,服务器端都有验证,会验证合法的接口
才会允许访问:看看服务器端的代码:
package com.company.project.core.filter;
import com.company.project.core.constant.ConstantKey;
import com.company.project.core.exception.TokenException;
import io.jsonwebtoken.*;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.util.DigestUtils;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
/**
* token的校验
* 该类继承自BasicAuthenticationFilter,在doFilterInternal方法中,
* 从http头的Authorization 项读取token数据,然后用Jwts包提供的方法校验token的合法性。
* 如果校验通过,就认为这是一个取得授权的合法请求
* @author LiuWenhao on 2018/05/27.
*/
public class AuthenticationFilter extends BasicAuthenticationFilter {
private static final Logger logger = LoggerFactory.getLogger(AuthenticationFilter.class);
public AuthenticationFilter(AuthenticationManager authenticationManager) {
super(authenticationManager);
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
String time = request.getHeader("APPDATE");
String key = request.getHeader("APPKEY");
String md5 = request.getHeader("APPSECRET");
//兼容websocket传参
// if(header == null || header.length()==0){
// header = request.getParameter("Authorization");
// }
// if (header == null || !header.startsWith("Bearer ")) {
// chain.doFilter(request, response);
// return;
// }
if(time == null || key == null|| md5 == null){
chain.doFilter(request, response);
}else{
UsernamePasswordAuthenticationToken authentication = getAuthentication(request);
SecurityContextHolder.getContext().setAuthentication(authentication);
chain.doFilter(request, response);
}
}
private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
try{
String time = request.getHeader("APPDATE");
String key = request.getHeader("APPKEY");
String md5 = request.getHeader("APPSECRET");
String secret = key;
for(int i=time.length()-1; i>=0; i--){
secret = time.charAt(i);
}
secret = "XXXXXX";
String cuMd5 = DigestUtils.md5DigestAsHex(secret.getBytes());
if (cuMd5.equals(md5)){
return new UsernamePasswordAuthenticationToken(cuMd5, null, new ArrayList<>());
}else{
System.out.println("cuMd5:" cuMd5 "reqMd5:" md5);
}
}catch (Exception e){
e.printStackTrace();
}
return null;
}
}
可以看到上面其实就是利用的spingsecurity的filter,拦截器来进行实现的,拦截所有的请求,在请求
头部获取,来的字符串,根据自己设计的规则,去生成一个md5字符串,看看这个md5字符串和,发过来的md5字符串是否一致,就可以验证是否合法.
而这里的问题就在于:
if (cuMd5.equals(md5)){
return new UsernamePasswordAuthenticationToken(cuMd5, null, new ArrayList<>());
}else{
System.out.println("cuMd5:" cuMd5 "reqMd5:" md5);
}
偶尔有时候,cuMd5,自己在后台计算的md5字符串,和发过来的md5字符串,不一样,这个时候,验证
失败,这个请求就不会放行,这个时候,就出现了上面的异常.
后来发现,因为这个cuMd5的计算是一个人做的,在android端的md5是另一个人做的,所以,
虽然都是对同样的字符串,进行md5加密,但是在android端md5加密字符串的那个人,加密出的
加密串,偶尔会首部,缺少一个字母...
public static String getMD5Str(String string) {
if (StringUtils.isEmpty(string)) {
return "";
}
MessageDigest md5 = null;
try {
md5 = MessageDigest.getInstance("MD5");
byte[] bytes = md5.digest(string.getBytes());
String result = "";
for (byte b : bytes) {
String temp = Integer.toHexString(b & 0xff);
if (temp.length() == 1) {
temp = "0" temp;
}
result = temp;
}
return result;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return "";
}
两遍都用上面这个加密方式的话是没问题的.
可以看到上面服务器端用的是:
secret = "XXXX";
String cuMd5 = DigestUtils.md5DigestAsHex(secret.getBytes()); 这个也是没问题的
但是之前android端用的:
public static String getMD5StrBack(String str) {
byte[] digest = null;
try {
MessageDigest md5 = MessageDigest.getInstance("md5");
digest = md5.digest(str.getBytes("utf-8"));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
//16是表示转换为16进制数
String md5Str = new BigInteger(1, digest).toString(16);
return md5Str;
}
这个是有问题的.
,