如何使用Java登录并从https网页下载文件?

3

我需要使用Java登录https网页并下载文件。 我事先知道所有的URL:

baseURL = // a https URL;
urlMap = new HashMap<String, URL>();
urlMap.put("login", new URL(baseURL, "exec.asp?login=username&pass=XPTO"));
urlMap.put("logout", new URL(baseURL, "exec.asp?exec.asp?page=999"));
urlMap.put("file", new URL(baseURL, "exec.asp?file=111"));

如果我在像火狐这样的浏览器中尝试所有这些链接,它们都有效。现在当我执行以下操作:
urlConnection = urlMap.get("login").openConnection();
urlConnection.connect();
BufferedReader in = new BufferedReader(
    new InputStreamReader(urlConnection.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null)
    System.out.println(inputLine);
in.close();

我刚刚再次获取了登录页面的HTML代码,但无法继续进行文件下载。
谢谢!
5个回答

5

我同意Alnitak的看法,问题很可能是存储和返回cookie。

我使用过另一个不错的选项Jakarta Commons中的HttpClient。

值得注意的是,如果这是您控制的服务器,则应该知道将用户名和密码作为查询字符串发送不安全(即使您正在使用HTTPS)。 HttpClient支持使用POST发送参数,您应该考虑使用。


1
使用GET方法如何会使它不安全?据我所知,在使用HTTPS时,传输到网络上的所有内容都是加密的,包括请求页面的地址。 - Kibbee
2
如果您正在使用HTTPS,基于URL的查询参数为什么不安全?HTTP请求与交换的其余部分一样被加密。通常在浏览器中不安全,因为该信息通常存储在历史记录中。 - Alan Krueger
尽管查询字符串在传输过程中被加密,但它们可能会暴露给浏览器插件、浏览器历史记录、在您自己的计算机上运行的其他应用程序,并很可能出现在服务器日志中。在不在应用程序内部加密的情况下将敏感数据包含在 URL 中是不好的做法。 - Jacob Mattison
1
我认为最佳实践是使用HTTPS上的HTTP基本身份验证。当然,如果这样可以减少维护服务器端代码量,那么你可以自己编写基于表单的身份验证。 - Mark Renouf

4

正如已经注意到的那样,您必须在请求之间保持会话 cookie(请参见CookieHandler)。

以下是一个示例实现:

class MyCookieHandler extends CookieHandler {

    private Map<String, List<String>> cookies = new HashMap<String, List<String>>();

    @Override
    public Map<String, List<String>> get(URI uri,
            Map<String, List<String>> requestHeaders) throws IOException {
        String host = uri.getHost();
        Map<String, List<String>> ret = new HashMap<String, List<String>>();
        synchronized (cookies) {
            List<String> store = cookies.get(host);
            if (store != null) {
                store = Collections.unmodifiableList(store);
                ret.put("Cookie", store);
            }
        }

        return Collections.unmodifiableMap(ret);
    }

    @Override
    public void put(URI uri, Map<String, List<String>> responseHeaders)
            throws IOException {
        List<String> newCookies = responseHeaders.get("Set-Cookie");
        if (newCookies != null) {
            String host = uri.getHost();
            synchronized (cookies) {
                List<String> store = cookies.get(host);
                if (store == null) {
                    store = new ArrayList<String>();
                    cookies.put(host, store);
                }
                store.addAll(newCookies);
            }
        }
    }

}

3

尽管您可能有其他导致登录请求无法使您登录的问题,但是如果不存储并返回登录页面生成的任何cookie,则不太可能能够继续访问下载页面。

这是因为HTTP本身是无状态的,因此在您当前的代码中,远程服务器无法知道第二个下载请求是否来自刚刚登录的同一用户。


2
我建议您查看Java CURL http://sourceforge.net/projects/javacurl。我以前使用过它来登录到https网站并下载内容,它具有欺骗浏览器ID等功能。这可能解决您被重定向回登录页面的问题。
虽然他们为此提供了一个eclipse插件,但我没有使用它也能正常工作。
或者您可以使用wget并从Java中调用它。

1

也许你想尝试一下HttpUnit。虽然它是为测试网站而编写的,但对于你的问题可能也有用。

从他们的网站上可以看到:

"... HttpUnit是用Java编写的,模拟了浏览器行为的相关部分,包括表单提交、JavaScript、基本的http身份验证、cookies和自动页面重定向,并允许Java测试代码以文本、XML DOM或包含表单、表格和链接的容器的形式检查返回的页面。"


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接