專案中上傳檔案到服務器,nagix設定了檔案最大為10M,如果移動端上傳檔案超過10M,就上傳失敗。我用的是android原生網路請求HttpUrlConnection,我希望上傳大于10M的檔案后,能夠得到response code和error message,但是實際上在我獲取response code的時候,這句代碼就拋出例外了,例外為下面三個(隨修改引數,報的例外是三個中的一個)
error asyncExecute:Write error: ssl=0x7ec7b80008: I/O error during system call, Connection reset by peer
javax.net.ssl.SSLException: Write error: ssl=0x7e67fae408: I/O error during system call, Broken pipe
java.net.SocketException: Connection reset
然后,我通過fiddler抓包,拿到的例外如下:
<html>
<head>
<title>413 Request Entity Too Large</title>
</head>
<body>
<center>
<h1>413 Request Entity Too Large</h1>
</center>
<hr>
<center>nginx/1.17.5</center>
</body>
<html>
然后問了一下后臺,為了負載均衡,特意在nagix上設定10M的限制。
大概原因是,上傳超過10M的檔案時,nginx檢查檔案超過設定的最大值,就斷開的connection,于是在getResponseCode或者getInputStream的時候,就直接拋例外了。
面對這種情況,我該如何拿到response code?
HttpUrlConnection設定代碼如下:
URL originUrl = new URL(url);
String protocol = originUrl.getProtocol();
if (TextUtils.equals(protocol, "http")) {
port = 80;
}
mURL = new URL(protocol, originUrl.getHost(), port, originUrl.getFile());
mConn = (HttpURLConnection) mURL.openConnection();
if (mConn instanceof HttpsURLConnection) {
selfSignedCertificate = true;
SSLCustomSocketFactory factory = new SSLCustomSocketFactory(selfSignedCertificate ? SSLCustomSocketFactory.getSocketFactory()
: (SSLSocketFactory) SSLSocketFactory.getDefault());
((HttpsURLConnection) mConn).setSSLSocketFactory(factory);
((HttpsURLConnection) mConn).setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
}
mConn.setRequestMethod("POST");
mConn.setDoOutput(true);
mConn.setDoInput(true);
mConn.setUseCaches(false);
mConn.setConnectTimeout(30000);
mConn.setReadTimeout(30000);
mConn.setRequestProperty("User-agent", "xxxx");//xxxx涉及到專案中資訊不展示
mConn.setRequestProperty("Connection", "Keep-Alive");
mConn.setRequestProperty("Charset", "UTF-8");
mConn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);
mConn.setRequestProperty("Expect", "100-Continue");
mConn.setChunkedStreamingMode(0);
//添加傳入的請求頭
for (Map.Entry<String, String> item : headers.entrySet()) {
mConn.setRequestProperty(item.getKey(), item.getValue());
}
mConn.connect();
//添加檔案
DataOutputStream out = new DataOutputStream(connect.getOutputStream());
//傳入的引數
out.write(params.getBytes());
out.flush();
StringBuffer strBuf = new StringBuffer();
for (String key : paramsMap.keySet()){
strBuf.append(TWO_HYPHENS);
strBuf.append(BOUNDARY);
strBuf.append(LINE_END);
strBuf.append("Content-Disposition: form-data; name=\"" + key + "\"");
strBuf.append(LINE_END);
strBuf.append("Content-Type: " + "text/plain" );
strBuf.append(LINE_END);
strBuf.append("Content-Length: "+paramsMap.get(key).length());
strBuf.append(LINE_END);
strBuf.append(LINE_END);
strBuf.append(paramsMap.get(key));
strBuf.append(LINE_END);
}
String paramsString = strBuf.toString();
out.write(paramsString.getBytes());
out.flush();
String fileName = UriUtils.getFileNameByUri(mContext, fileUri);
String mimeType = UriUtils.getMimeType(mContext, fileUri);
long fileLength = UriUtils.getFileLength(mContext, fileUri);
if(!TextUtils.isEmpty(filename)) {
fileName = filename;
}
//添加檔案頭
out.write(getFileHeaderParamsString(fileKey, fileName, mimeType, fileLength).getBytes());
//添加檔案體
String filePath = UriUtils.getFilePath(fileUri);
InputStream in = null;
try {
if (!TextUtils.isEmpty(filePath) && new File(filePath).exists()) {
in = new FileInputStream(new File(filePath));
} else {
in = mContext.getContentResolver().openInputStream(fileUri);
}
byte[] tmp = new byte[2048];
int l;
long sum = 0;
while ((l = in.read(tmp)) != -1) {
out.write(tmp, 0, l);
sum += l;
if (callback != null) {
callback.onProgress(fileLength, sum);
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (in != null) {
in.close();
}
}
//添加檔案尾
out.write(getFileEndString().getBytes());
out.flush();
HttpResponse response = new HttpResponse();
//上傳大檔案執行到這里就會拋出例外,但是拿到例外不是所希望的,然后呢,也沒有相應碼
response.code = mConn.getResponseCode();
if(response.code == HttpURLConnection.HTTP_OK) {
response.contentLength = mConn.getContentLength();
response.inputStream = mConn.getInputStream();
response.content = parseStream(response.inputStream);
}else {
response.errorStream = mConn.getErrorStream();
response.content = parseStream(response.errorStream);
}
//下面就是對不同code的處理邏輯
//這是SSLSocketFactory類
public static class SSLCustomSocketFactory extends SSLSocketFactory {
private static final String TAG = "SSLCustomSocketFactory";
private static final String[] TLS_SUPPORT_VERSION = {"TLSv1.1", "TLSv1.2"};
private static final String KEY_PASS = "";
final SSLSocketFactory delegate;
static SSLContext sslContext;
static SSLSocketFactory mSocketFactory;
public SSLCustomSocketFactory(SSLSocketFactory base) {
delegate = base;
}
@Override
public String[] getDefaultCipherSuites() {
return delegate.getDefaultCipherSuites();
}
@Override
public String[] getSupportedCipherSuites() {
return delegate.getSupportedCipherSuites();
}
@Override
public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
return patch(delegate.createSocket(s, host, port, autoClose));
}
@Override
public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
return patch(delegate.createSocket(host, port));
}
@Override
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
return patch(delegate.createSocket(host, port, localHost, localPort));
}
@Override
public Socket createSocket(InetAddress host, int port) throws IOException {
return patch(delegate.createSocket(host, port));
}
@Override
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
return patch(delegate.createSocket(address, port, localAddress, localPort));
}
private Socket patch(Socket s) {
if(s instanceof SSLSocket) {
((SSLSocket) s).setEnabledProtocols(TLS_SUPPORT_VERSION);
}
return s;
}
public static synchronized SSLSocketFactory getSocketFactory() {
if(mSocketFactory == null) {
try {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
AssetManager am = context().getAssets();
String[] certsPaths = am.list("xxx_certs");//設計到專案,修改為xxx
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
for (int i = 0; i < certsPaths.length; i++) {
String certPath = certsPaths[i];
InputStream caInput = null;
try {
caInput = am.open("xxxx_certs/" + certPath);
Certificate ca = cf.generateCertificate(caInput);
System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
keyStore.setCertificateEntry("ca" + i, ca);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (caInput != null) {
caInput.close();
}
}
}
//取得SSL的SSLContext實體
sslContext = SSLContext.getInstance("TLS");
TrustManagerFactory tmf = TrustManagerFactory.
getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(keyStore);
sslContext.init(null, tmf.getTrustManagers(), null);
mSocketFactory = sslContext.getSocketFactory();
} catch (Throwable e) {
e.printStackTrace();
}
}
return mSocketFactory;
}
}
跪求大神解惑,面對這種情況,我該如何處理?
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/30530.html
標籤:Android
