我正在尝试使用 Apache HttpClient 库通过 POST
方法上传文件。
我使用了抢占式基本身份验证的示例代码 here :
package ahcs;
// many imports, press ctrl-o in eclipse
public class App {
static final String url = "http://127.0.0.1:64738/test/";
static final String content = "test\nfile\ndata";
static final String httpUser = "testuser";
static final String httpPasswd = "testPassword";
static final String fileUploadFieldName = "uploadData";
static final String fileName = "upload.dat";
public static void main(String[] args) {
System.err.println("Uploading to URL " + url);
CloseableHttpClient httpclient = HttpClientBuilder.create().build();
HttpPost httpPost = new HttpPost(url);
httpPost.setProtocolVersion(HttpVersion.HTTP_1_1);
MultipartEntityBuilder mpEntityBuilder =
MultipartEntityBuilder.create();
mpEntityBuilder.setMode(HttpMultipartMode.RFC6532);
mpEntityBuilder.addBinaryBody(fileUploadFieldName,
content.getBytes(), ContentType.DEFAULT_BINARY, fileName);
httpPost.setEntity(mpEntityBuilder.build());
System.err.println("executing request " + httpPost.getRequestLine());
HttpEntity resEntity = null;
try {
// Really simple HTTP Authentification, grat Apache
HttpHost httpHost = URIUtils.extractHost(new URI(url));
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(AuthScope.ANY,
new UsernamePasswordCredentials(httpUser, httpPasswd));
AuthCache authCache = new BasicAuthCache();
authCache.put(httpHost, new BasicScheme());
HttpClientContext context = HttpClientContext.create();
context.setCredentialsProvider(credsProvider);
context.setAuthCache(authCache);
HttpResponse response = httpclient.execute(httpPost);
resEntity = response.getEntity();
System.err.println(response.getStatusLine().toString());
if (resEntity != null) {
System.err.println(EntityUtils.toString(resEntity));
}
int status = response.getStatusLine().getStatusCode();
if (status != HttpStatus.SC_OK) {
throw new HttpResponseException(status,
"Upload error! (" + status + ")");
}
EntityUtils.consume(resEntity);
httpclient.close();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
不幸的是,它没有达到我想要的效果。 apache httpclient 给出的请求是这样的(我通过使用 nc -p 64738 -l
命令从命令行监听得到这个):
POST /test/ HTTP/1.1
Content-Length: 249
Content-Type: multipart/form-data; boundary=PIrvSJ07MLxTV2rC4d-5ZfoL3CvJFJdJqO4i
Host: 127.0.0.1:64738
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.5.4 (Java/1.8.0_151)
Accept-Encoding: gzip,deflate
--PIrvSJ07MLxTV2rC4d-5ZfoL3CvJFJdJqO4i
Content-Disposition: form-data; name="uploadData"; filename="upload.dat"
Content-Type: application/octet-stream
Content-Transfer-Encoding: binary
test
file
data
--PIrvSJ07MLxTV2rC4d-5ZfoL3CvJFJdJqO4i--
正如我们所见,一切正常,只是缺少身份验证 header 。
为什么会这样呢?有什么错误?
最佳答案
根据RFC7617您只需要一个 header “Authorization”,值为“Basic” + Base64 编码的登录名:密码即可成功通过基本授权。
您的代码是正确的,除了一件事 - 当您调用 httpPost.execute 时,您没有传递执行上下文,并且根本没有使用 AuthCache 和 CredentialsProvider。
package ahcs;
// many imports, press ctrl-o in eclipse
public class App {
static final String url = "http://127.0.0.1:64738/test/";
static final String content = "test\nfile\ndata";
static final String httpUser = "testuser";
static final String httpPasswd = "testPassword";
static final String fileUploadFieldName = "uploadData";
static final String fileName = "upload.dat";
public static void main(String[] args) {
System.err.println("Uploading to URL " + url);
CloseableHttpClient httpclient = HttpClientBuilder.create().build();
HttpPost httpPost = new HttpPost(url);
httpPost.setProtocolVersion(HttpVersion.HTTP_1_1);
MultipartEntityBuilder mpEntityBuilder =
MultipartEntityBuilder.create();
mpEntityBuilder.setMode(HttpMultipartMode.RFC6532);
mpEntityBuilder.addBinaryBody(fileUploadFieldName,
content.getBytes(), ContentType.DEFAULT_BINARY, fileName);
httpPost.setEntity(mpEntityBuilder.build());
System.err.println("executing request " + httpPost.getRequestLine());
HttpEntity resEntity = null;
try {
// Really simple HTTP Authentification, grat Apache
HttpHost httpHost = URIUtils.extractHost(new URI(url));
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(AuthScope.ANY,
new UsernamePasswordCredentials(httpUser, httpPasswd));
AuthCache authCache = new BasicAuthCache();
authCache.put(httpHost, new BasicScheme());
HttpClientContext context = HttpClientContext.create();
context.setCredentialsProvider(credsProvider);
context.setAuthCache(authCache);
// context was missed
HttpResponse response = httpclient.execute(httpPost, context);
resEntity = response.getEntity();
System.err.println(response.getStatusLine().toString());
if (resEntity != null) {
System.err.println(EntityUtils.toString(resEntity));
}
int status = response.getStatusLine().getStatusCode();
if (status != HttpStatus.SC_OK) {
throw new HttpResponseException(status,
"Upload error! (" + status + ")");
}
EntityUtils.consume(resEntity);
httpclient.close();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
但是对于基本身份验证,使用此 API 可能有点冗长,它旨在支持许多不同的授权方案。
如果您知道服务器将使用什么字符集来解码授权 header (假设它是 UTF-8),您可以编写一行代码:
httpPost.setHeader("Authorization", "Basic " + Base64.getEncoder().encodeToString((httpUser + ':' + httpPasswd).getBytes("UTF-8")));
关于java - 由于神秘原因,具有 POST 文件上传功能的 Apache HttpClient 无法进行基本身份验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48400808/