java - 由于神秘原因,具有 POST 文件上传功能的 Apache HttpClient 无法进行基本身份验证

标签 java http post apache-httpclient-4.x http-authentication

我正在尝试使用 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/

相关文章:

java - 使用 Gmail 从 Spring Boot 应用程序发送电子邮件

有效负载的 ASP.net MVC HTTP 请求错误

json - 如何使用 POST 方法获取 JSON 对象并将其映射到 spring 3.0 Controller 中的对象?

传递数据时python套接字http库发布请求不起作用

java - 在字符串数组中搜索字符串

java - 如何改变TextPane的大小?

java - Android - 服务器无法处理您的 apk - 大小限制?

html - angular2 : Supplied parameters do not match any signature of call target, 即使我有所有需要的参数

java - url 中的大字符串作为参数 carte pentaho

vb.net - 将多部分表单发布到 Bamboo API