美文网首页
解析HttpURLConnection与代理服务器

解析HttpURLConnection与代理服务器

作者: 骚的掉渣 | 来源:发表于2016-10-01 18:44 被阅读530次

    目前网络上最流行的协议就是HTTP协议。HTTP协议有许多优点,例如它能够穿越防火墙。同时HTTP也是很多其他协议的基础,例如SOAP协议就是建立在HTTP协议之上的。

    Java通过两种API对HTTP提供支持,一种是servlet API,它覆盖了服务器端的编程问题;另一种是java.net包,它通过HttpURLConnection类在客户端提供了对HTTP协议的支持。但是我在使用servlet API的时候曾经遇到过一些问题。本文将介绍我曾遇到过的一些问题和相应的解决办法。

    基础知识

    通常在企业网络中,一个终端通过代理服务器同互联网连接起来,代理服务器负责监视网络流量和执行安全规则。在java.net API中,软件可以通过两个属性来支持代理服务器,它们分别是http.proxyHost和http.proxyPort。它们必须被设定为相应的代理服务器和端口,下面的代码展示了如何设定这两个属性:

    String url = "http://www.digitalcq.com/";
    proxy = "proxy.digitalcq.com";
    port = "8080";
    URL server = new URL(url);
    Properties systemProperties =System.getProperties();
    systemProperties.setProperty("http.proxyHost",proxy);
    systemProperties.setProperty("http.proxyPort",port);
    HttpURLConnection connection = (HttpURLConnection)server.openConnection();
    connection.connect();
    InputStream in = connection.getInputStream();
    readResponse(in);
    

    在上面的程序中,你需要根据实际情况设定代理服务器和端口。如果你不知道该如何设置的话,可以询问你们公司的网络管理员。

    使用验证

    通常公司会要求员工在连接到互联网之前登录到代理服务器。通过登录这种机制使公司可以更好的监控员工对互联网的使用,例如监控员工都访问了哪些网站。HttpURLConnection通过验证类支持代理服务器验证。下面是一个如何利用HttpURLConnection类进行验证的例子。首先需要实现一个验证者:

    public class SimpleAuthenticator extends Authenticator {
            private String username, password;
    
            public SimpleAuthenticator(String username, String password) {
                this.username = username;
                this.password = password;
            }
    
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(username, password.toCharArray());
            }
        }
    

    然后,通过Authenticator.setDefault()方法注册验证者:

            String url = "http://www.digitalcq.com/";
            proxy="proxy.digitalcq.com";
            port="8080";
            username="usr";
            password="pwd";
            Authenticator.setDefault(new SimpleAuthenticator(username,password));
            URL server = new URL(url);
            Properties systemProperties = System.getProperties();
            systemProperties.setProperty("http.proxyHost",proxy);
            systemProperties.setProperty("http.proxyPort",port);
            HttpURLConnection connection = (HttpURLConnection) server.openConnection();
            connection.connect();
            InputStream in = connection.getInputStream();
    
            readResponse(in);
    

    问题

    上面介绍的都是HttpURLConnection类能够正常工作的情况。但是我在实际情况中遇到了一些网络,在这些网络中,HttpURLConnection类无法正常工作。最后我发现关键的问题在于使用了不正确的DNS配置。在实际情况中,HttpURLConnection类总是先尝试利用DNS服务器来解析地址名称。通常情况下,这种尝试会失败,而代理服务器会将连接重新定向。但是某些DNS服务器会返回一些不正确的响应,从而导致程序抛出UnknownHostException异常。作为一个程序员,系统不会为了你的程序更改DNS服务器的配置,因此你需要找出解决这个问题的方法。我的方案是通过自己实现HTTP协议来解决这个问题。例如一个GET命令可以用下面的代码来实现:

            String url = "http://www.digitalcq.com/";
            proxy = "proxy.digitalcq.com";
            port = "8080";
            authentication = "usr:pwd";
            URL server = new URL(url);
            Socket socket = new Socket(proxy, port);
            Writer writer = new OutputStreamWriter(socket.getOutputStream(),"US-ASCII");
            writer.write("GET "+server.toExternalForm()+" HTTP/1.0\r\n");
            writer.write("Host: "+server.getHost()+"\r\n");
            writer.write("Proxy-Authorization: Basic "+new sun.misc.BASE64Encoder().encode(authentication.getBytes())+"\r\n\r\n");
            writer.flush();
            BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), "US-ASCII"));
            String line = reader.readLine();
            if(line!=null&&line.startsWith("HTTP/")){
                int sp = line.indexOf(' ');
                String status = line.substring(sp + 1, sp + 4);
                if (status.equals("200")) {
                    while (line.length() != 0)
                        line = reader.readLine();
                    readResponse(reader);
                } else
                    throw new FileNotFoundException("Host reports error " + status);
            }else 
                throw new IOException("Bad protocol");
            reader.close();
            writer.close();
            socket.close();
    

    在上面的代码中,大家可以注意到代理服务器的用户名和密码的格式是:

    username:password
    

    并且程序对它们基于Base 64进行了编码。

    相关文章

      网友评论

          本文标题:解析HttpURLConnection与代理服务器

          本文链接:https://www.haomeiwen.com/subject/olnryttx.html