栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

HTTPS URL的基本代理身份验证返回HTTP / 1.0 407必需的代理身份验证

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

HTTPS URL的基本代理身份验证返回HTTP / 1.0 407必需的代理身份验证

您可以自己扩展

ProxiedHttpsConnection
和处理所有与底层相关的内容。

需要执行以下步骤以通过HTTP代理与https网站建立连接:

注意:与代理服务器和http服务器的通信应使用ASCII7。

  1. 发送
    ConNECT stackoverflow.com:443 HTTP/1.0rn
    给代理
  2. 发送您的身份验证:
    Proxy-Authorization: Basic c2F5WW91SGF2ZVNlZW5UaGlzSW5UaGVDb21tZW50cw==rn
  3. 结束第一个请求:
    rn
  4. 阅读来自代理的响应,直到看到组合“ r n r n”。
  5. 解析您从代理获得的响应的第一行,并检查其是否以开头
    HTTP/1.0 200
  6. 在现有连接上就地启动SSL会话。
  7. 发送http请求的开始:
    GET /questions/3304006/persistent-httpurlconnection-in-java HTTP/1.0rn
  8. 设置正确的主机头:
    Host: stackoverflow.comrn
  9. 将请求结束到http服务器:
    rn
  10. 阅读直到
    rn
    并将第一行解析为状态消息
  11. 读取直到流结束以获取请求正文

当我们想要实现HttpUrlConnection类时,我们还需要考虑以下几点:

  • 在构造类时,该类应存储数据以备将来连接,但不要直接使其
  • 可以按任何顺序调用任何方法
  • 闭合
    OutputStream
    意味着数据传输已经完成,而不是意味着连接必须完成
  • 每个api以不同的顺序使用方法
  • HTTP标头不区分大小写,Java映射区分大小写。

迅速地说,有很多陷阱

在我设计的类中,它使用布尔标志来记住

connect
方法和
afterPostClosure
方法是否被调用,并且还具有
getInputStream()
OutputStream
关闭之前调用if的支持。

此类还对套接字返回的流使用了尽可能少的包装,以防止过于复杂。

public class ProxiedHttpsConnection extends HttpURLConnection {    private final String proxyHost;    private final int proxyPort;    private static final byte[] newline = "rn".getBytes();//should be "ASCII7"    private Socket socket;    private final Map<String, List<String>> headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);    private final Map<String, List<String>> sendheaders = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);    private final Map<String, List<String>> proxyheaders = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);    private final Map<String, List<String>> proxyreturnheaders = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);    private int statusCode;    private String statusLine;    private boolean isDoneWriting;    public ProxiedHttpsConnection(URL url, String proxyHost, int proxyPort, String username, String password) throws IOException {        super(url);        socket = new Socket();        this.proxyHost = proxyHost;        this.proxyPort = proxyPort;        String enpred = base64.enpre((username + ":" + password).getBytes())     .replace("rn", "");        proxyheaders.put("Proxy-Authorization", new ArrayList<>(Arrays.asList("Basic " + enpred)));    }    @Override    public OutputStream getOutputStream() throws IOException {        connect();        afterWrite();        return new FilterOutputStream(socket.getOutputStream()) { @Override public void write(byte[] b, int off, int len) throws IOException {     out.write(String.valueOf(len).getBytes());     out.write(newline);     out.write(b, off, len);     out.write(newline); } @Override public void write(byte[] b) throws IOException {     out.write(String.valueOf(b.length).getBytes());     out.write(newline);     out.write(b);     out.write(newline); } @Override public void write(int b) throws IOException {     out.write(String.valueOf(1).getBytes());     out.write(newline);     out.write(b);     out.write(newline); } @Override public void close() throws IOException {     afterWrite(); }        };    }    private boolean afterwritten = false;    @Override    public InputStream getInputStream() throws IOException {        connect();        return socket.getInputStream();    }    @Override    public void setRequestMethod(String method) throws ProtocolException {        this.method = method;    }    @Override    public void setRequestProperty(String key, String value) {        sendheaders.put(key, new ArrayList<>(Arrays.asList(value)));    }    @Override    public void addRequestProperty(String key, String value) {        sendheaders.computeIfAbsent(key, l -> new ArrayList<>()).add(value);    }    @Override    public Map<String, List<String>> getHeaderFields() {        return headers;    }    @Override    public void connect() throws IOException {        if (connected) { return;        }        connected = true;        socket.setSoTimeout(getReadTimeout());        socket.connect(new InetSocketAddress(proxyHost, proxyPort), getConnectTimeout());        StringBuilder msg = new StringBuilder();        msg.append("ConNECT ");        msg.append(url.getHost());        msg.append(':');        msg.append(url.getPort() == -1 ? 443 : url.getPort());        msg.append(" HTTP/1.0rn");        for (Map.Entry<String, List<String>> header : proxyheaders.entrySet()) { for (String l : header.getValue()) {     msg.append(header.getKey()).append(": ").append(l);     msg.append("rn"); }        }        msg.append("Connection: closern");        msg.append("rn");        byte[] bytes;        try { bytes = msg.toString().getBytes("ASCII7");        } catch (UnsupportedEncodingException ignored) { bytes = msg.toString().getBytes();        }        socket.getOutputStream().write(bytes);        socket.getOutputStream().flush();        byte reply[] = new byte[200];        byte header[] = new byte[200];        int replyLen = 0;        int headerLen = 0;        int newlinesSeen = 0;        boolean headerDone = false;                InputStream in = socket.getInputStream();        while (newlinesSeen < 2) { int i = in.read(); if (i < 0) {     throw new IOException("Unexpected EOF from remote server"); } if (i == 'n') {     if (newlinesSeen != 0) {         String h = new String(header, 0, headerLen);         String[] split = h.split(": ");         if (split.length != 1) {  proxyreturnheaders.computeIfAbsent(split[0], l -> new ArrayList<>()).add(split[1]);         }     }     headerDone = true;     ++newlinesSeen;     headerLen = 0; } else if (i != 'r') {     newlinesSeen = 0;     if (!headerDone && replyLen < reply.length) {         reply[replyLen++] = (byte) i;     } else if (headerLen < reply.length) {         header[headerLen++] = (byte) i;     } }        }        String replyStr;        try { replyStr = new String(reply, 0, replyLen, "ASCII7");        } catch (UnsupportedEncodingException ignored) { replyStr = new String(reply, 0, replyLen);        }        // Some proxies return http/1.1, some http/1.0 even we asked for 1.0        if (!replyStr.startsWith("HTTP/1.0 200") && !replyStr.startsWith("HTTP/1.1 200")) { throw new IOException("Unable to tunnel. Proxy returns "" + replyStr + """);        }        SSLSocket s = (SSLSocket) ((SSLSocketFactory) SSLSocketFactory.getDefault())     .createSocket(socket, url.getHost(), url.getPort(), true);        s.startHandshake();        socket = s;        msg.setLength(0);        msg.append(method);        msg.append(" ");        msg.append(url.toExternalForm().split(String.valueOf(url.getPort()), -2)[1]);        msg.append(" HTTP/1.0rn");        for (Map.Entry<String, List<String>> h : sendheaders.entrySet()) { for (String l : h.getValue()) {     msg.append(h.getKey()).append(": ").append(l);     msg.append("rn"); }        }        if (method.equals("POST") || method.equals("PUT")) { msg.append("Transfer-Encoding: Chunkedrn");        }        msg.append("Host: ").append(url.getHost()).append("rn");        msg.append("Connection: closern");        msg.append("rn");        try { bytes = msg.toString().getBytes("ASCII7");        } catch (UnsupportedEncodingException ignored) { bytes = msg.toString().getBytes();        }        socket.getOutputStream().write(bytes);        socket.getOutputStream().flush();    }    private void afterWrite() throws IOException {        if (afterwritten) { return;        }        afterwritten = true;        socket.getOutputStream().write(String.valueOf(0).getBytes());        socket.getOutputStream().write(newline);        socket.getOutputStream().write(newline);        byte reply[] = new byte[200];        byte header[] = new byte[200];        int replyLen = 0;        int headerLen = 0;        int newlinesSeen = 0;        boolean headerDone = false;                InputStream in = socket.getInputStream();        while (newlinesSeen < 2) { int i = in.read(); if (i < 0) {     throw new IOException("Unexpected EOF from remote server"); } if (i == 'n') {     if (headerDone) {         String h = new String(header, 0, headerLen);         String[] split = h.split(": ");         if (split.length != 1) {  headers.computeIfAbsent(split[0], l -> new ArrayList<>()).add(split[1]);         }     }     headerDone = true;     ++newlinesSeen;     headerLen = 0; } else if (i != 'r') {     newlinesSeen = 0;     if (!headerDone && replyLen < reply.length) {         reply[replyLen++] = (byte) i;     } else if (headerLen < header.length) {         header[headerLen++] = (byte) i;     } }        }        String replyStr;        try { replyStr = new String(reply, 0, replyLen, "ASCII7");        } catch (UnsupportedEncodingException ignored) { replyStr = new String(reply, 0, replyLen);        }                if ((!replyStr.startsWith("HTTP/1.0 200")) && !replyStr.startsWith("HTTP/1.1 200")) { throw new IOException("Server returns "" + replyStr + """);        }    }    @Override    public void disconnect() {        try { socket.close();        } catch (IOException ex) { Logger.getLogger(ProxiedHttpsConnection.class.getName()).log(Level.SEVERE, null, ex);        }    }    @Override    public boolean usingProxy() {        return true;    }}

上面代码的当前错误:

  • 发布期间错误未关闭流
  • 在首次与代理联系时发生错误时,流未关闭
  • 它不支持http重定向
  • 它不支持诸如分块和gzip编码之类的http 1.1,但这并不是问题,因为我们宣布自己为http1.0客户端。

上面的代码可以像这样使用:

    ProxiedHttpsConnection n = new ProxiedHttpsConnection( new URL("https://stackoverflow.com:443/questions/3304006/persistent-httpurlconnection-in-java"),  "proxy.example.com", 8080, "root", "flg83yvem#");    n.setRequestMethod("GET");    n.addRequestProperty("User-Agent", "Java test https://stackoverflow.com/users/1542723/ferrybig");    //try (OutputStream out = n.getOutputStream()) {    //  out.write("Hello?".getBytes());    //}    try (InputStream in = n.getInputStream()) {        byte[] buff = new byte[1024];        int length;        while ((length = in.read(buff)) >= 0) { System.out.write(buff, 0, length);        }    }

如果要将它与一种代理选择器一起使用,则应检查url的协议,以查看其http还是https,如果它的http,则不要使用此类,而是手动附加标头,例如:

httpURLConnection.setRequestProperty("Proxy-Authorization", "Basic " + enpred);

为什么不使用httpsUrlConnection.setSSLSocketFactory

虽然Java有此方法,但尝试使用它会向您展示为什么它不起作用,但Java只会

createSocket(Socket s, String host,int port, booleanautoClose)
通过已打开的连接不断调用,从而无法手动进行代理操作。



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/414437.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号