英文:
Trying to run a simple example of Java NIO SSL to load the contents of https://www.amazon.com but getting 400 Bad Request
问题
尝试了一切,但还是不起作用 :(
完整的代码和示例可以在此处找到:https://examples.javacodegeeks.com/core-java/nio/java-nio-ssl-example/
此外,您可以通过单击此处下载完整的源代码(仅有3个类):https://examples.javacodegeeks.com/wp-content/uploads/2015/12/NioSSLExample.zip
感谢任何帮助!
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLSession;
public class NioSSLExample
{
public static void main(String[] args) throws Exception
{
InetSocketAddress address = new InetSocketAddress("www.amazon.com", 443);
Selector selector = Selector.open();
SocketChannel channel = SocketChannel.open();
channel.connect(address);
channel.configureBlocking(false);
int ops = SelectionKey.OP_CONNECT | SelectionKey.OP_READ;
SelectionKey key = channel.register(selector, ops);
// create the worker threads
final Executor ioWorker = Executors.newSingleThreadExecutor();
final Executor taskWorkers = Executors.newFixedThreadPool(2);
// create the SSLEngine
final SSLEngine engine = SSLContext.getDefault().createSSLEngine();
engine.setUseClientMode(true);
engine.beginHandshake();
final int ioBufferSize = 32 * 1024;
final NioSSLProvider ssl = new NioSSLProvider(key, engine, ioBufferSize, ioWorker, taskWorkers)
{
@Override
public void onFailure(Exception ex)
{
System.out.println("握手失败");
ex.printStackTrace();
}
@Override
public void onSuccess()
{
System.out.println("握手成功");
SSLSession session = engine.getSession();
try
{
System.out.println("本地主体:" + session.getLocalPrincipal());
System.out.println("远程主体:" + session.getPeerPrincipal());
System.out.println("密码套件:" + session.getCipherSuite());
}
catch (Exception exc)
{
exc.printStackTrace();
}
//HTTP 请求
StringBuilder http = new StringBuilder();
http.append("GET / HTTP/1.0\r\n");
http.append("Connection: close\r\n");
http.append("\r\n");
byte[] data = http.toString().getBytes();
ByteBuffer send = ByteBuffer.wrap(data);
this.sendAsync(send);
}
@Override
public void onInput(ByteBuffer decrypted)
{
// HTTP 响应
byte[] dst = new byte[decrypted.remaining()];
decrypted.get(dst);
String response = new String(dst);
System.out.print(response);
System.out.flush();
}
@Override
public void onClosed()
{
System.out.println("SSL 会话已关闭");
}
};
// NIO 选择器
while (true)
{
key.selector().select();
Iterator keys = key.selector().selectedKeys().iterator();
while (keys.hasNext())
{
keys.next();
keys.remove();
ssl.processInput();
}
}
}
}
英文:
Trying everyting but it does not work
The complete code and example can be found here: https://examples.javacodegeeks.com/core-java/nio/java-nio-ssl-example/
Also you can download the full source (it is only 3 classes) by clicking here: https://examples.javacodegeeks.com/wp-content/uploads/2015/12/NioSSLExample.zip
Thanks for any help!
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLSession;
public class NioSSLExample
{
public static void main(String[] args) throws Exception
{
InetSocketAddress address = new InetSocketAddress("www.amazon.com", 443);
Selector selector = Selector.open();
SocketChannel channel = SocketChannel.open();
channel.connect(address);
channel.configureBlocking(false);
int ops = SelectionKey.OP_CONNECT | SelectionKey.OP_READ;
SelectionKey key = channel.register(selector, ops);
// create the worker threads
final Executor ioWorker = Executors.newSingleThreadExecutor();
final Executor taskWorkers = Executors.newFixedThreadPool(2);
// create the SSLEngine
final SSLEngine engine = SSLContext.getDefault().createSSLEngine();
engine.setUseClientMode(true);
engine.beginHandshake();
final int ioBufferSize = 32 * 1024;
final NioSSLProvider ssl = new NioSSLProvider(key, engine, ioBufferSize, ioWorker, taskWorkers)
{
@Override
public void onFailure(Exception ex)
{
System.out.println("handshake failure");
ex.printStackTrace();
}
@Override
public void onSuccess()
{
System.out.println("handshake success");
SSLSession session = engine.getSession();
try
{
System.out.println("local principal: " + session.getLocalPrincipal());
System.out.println("remote principal: " + session.getPeerPrincipal());
System.out.println("cipher: " + session.getCipherSuite());
}
catch (Exception exc)
{
exc.printStackTrace();
}
//HTTP request
StringBuilder http = new StringBuilder();
http.append("GET / HTTP/1.0\r\n");
http.append("Connection: close\r\n");
http.append("\r\n");
byte[] data = http.toString().getBytes();
ByteBuffer send = ByteBuffer.wrap(data);
this.sendAsync(send);
}
@Override
public void onInput(ByteBuffer decrypted)
{
// HTTP response
byte[] dst = new byte[decrypted.remaining()];
decrypted.get(dst);
String response = new String(dst);
System.out.print(response);
System.out.flush();
}
@Override
public void onClosed()
{
System.out.println("ssl session closed");
}
};
// NIO selector
while (true)
{
key.selector().select();
Iterator keys = key.selector().selectedKeys().iterator();
while (keys.hasNext())
{
keys.next();
keys.remove();
ssl.processInput();
}
}
}
}
答案1
得分: 1
http.append("GET / HTTP/1.0\r\n")
http.append("Connection: close\r\n")
http.append("\r\n")
虽然从理论上讲,这是一个正确的 HTTP/1.0 请求,但在实际中,大多数系统现在要求包含一个 `Host` 头部。虽然这只在 HTTP/1.1 下是必需的,但如果一个 IP 地址托管多个域名,则是必需的:
http.append("GET / HTTP/1.0\r\n")
http.append("Host: www.amazon.com\r\n")
http.append("\r\n")
此外,请注意 `Connection: close` 是不必要的,因为它在 HTTP/1.0 中是隐含的(但在 HTTP/1.1 中不是)。
除此之外,HTTP 比这个简单的请求复杂得多,即使这个请求也有问题,正如你所看到的。如果你需要自己实现它,请阅读标准,而不是假设服务器的响应方式或只看一些示例。
英文:
http.append("GET / HTTP/1.0\r\n");
http.append("Connection: close\r\n");
http.append("\r\n");
While this is in theory a correct HTTP/1.0 request in practice, most systems today require that a Host
header is included. While this is mandatory only with HTTP/1.1 it is needed if an IP address hosts multiple domains:
http.append("GET / HTTP/1.0\r\n");
http.append("Host: www.amazon.com\r\n");
http.append("\r\n");
Also note that the Connection: close
is unnecessary since it is implicit with HTTP/1.0 (but not with HTTP/1.1).
Apart from that HTTP is way more complex than this simple request and even this one had its problems as you saw. If you need to implement it for yourself please study the standards instead of making assumptions of how servers react or looking only at a few examples.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论