-->

Using Apache HttpComponents for http requests with

2020-07-19 15:43发布

问题:

Quick background.

CFHTTP doesn't support Windows NTLM/Authenticate authentication, only basic authentication. I need to make http requests that will have to authenticate against NTLM, so I've ended up rolling my own version of CFHTTP.

I found Terry Ryan's article that uses the apache httpclient version 3.1 to perform digest authentication and have built upon that using version 4.1.2 instead which includes NTLM functionality.

I have a function that will perform a get request and then other functions to handle returning a structure that looks like the cfhttp result set. The changes I made are based on the authentication tutorial example.

public any function httpRequest(url,username,password,domain) {
    var httpClient = createObject("java","org.apache.http.impl.client.DefaultHttpClient");
    var authScope = createObject("java","org.apache.http.auth.AuthScope");
    var httpCredentials = createObject("java","org.apache.http.auth.NTCredentials");
    var httpGet = createObject("java","org.apache.http.client.methods.HttpGet");
    var jURL = createObject("java", "java.net.URL").init(arguments.url);
    var host = jURL.getHost();
    var path = jURL.getPath();
    var httpHostTarget = createObject("java","org.apache.http.HttpHost").init(host,80,"http");
    var localContext = createObject("java","org.apache.http.protocol.BasicHttpContext");
    var httpContent = {};
    var response = '';

    if (len(arguments.username) and len(arguments.password) gt 0){
        httpCredentials.init(arguments.Username, arguments.password, cgi.remote_host,arguments.domain);
        httpClient.getCredentialsProvider().setCredentials(authScope.ANY, httpCredentials);
    }

    if (!Len(path)) path = "/";
    httpGet.init(path);

    response = httpClient.execute(httpHostTarget, httpget, localContext);

    httpContent = convertHttpClientResponseToCFHTTPFormat(response);

    httpClient.getConnectionManager().shutdown();

    return httpContent;
}

This was working fine until I altered the function to perform the authentication.

Unfortunately I'm now getting :

The execute method was not found.

Either there are no methods with the specified method name and argument types or the execute method is overloaded with argument types that ColdFusion cannot decipher reliably. ColdFusion found 2 methods that match the provided arguments. If this is a Java object and you verified that the method exists, use the javacast function to reduce ambiguity.

As far as I can tell there is only one matching execute() function in HttpClient for the object classes passed to it, so I'm a little confused. JavaCast doesn't allow you to cast to complex objects or super types, so that didn't work.

Can anyone suggest how I can get this to work? How can I reduce the ambiguity?

回答1:

Looking at the error, it's getting confused between two execute methods that have the same number of parameters. Although I don't know why it is...

Anyway, I found a way around the error. It involves pulling the method you're after out of the class and invoking it directly. If ColdFusion was happier with casting Java objects life might be easier.

//response = httpClient.execute(httpHostTarget, httpget, localContext);

classes = [httpHostTarget.getClass(), CreateObject('java', 'org.apache.http.HttpRequest').getClass(), CreateObject('java', 'org.apache.http.protocol.HttpContext').getClass()];
method = httpClient.getClass().getMethod('execute', classes);
params = [httpHostTarget, httpget, localContext];
response = method.invoke(httpClient, params);

There may be another way of doing this (casting instead) but it's all I've got ;)



回答2:

As a guess, could you be loading the wrong version of the .jars ? You don't seem to be using JavaLoader like Ryan did...