我正在编写一个基于Netty的HTTP/2服务,它执行“服务器发送事件”(SSE),我需要编写一个HTTP/2测试客户端类,用于集成测试,但我很难确定如何设置客户端管道,以便从服务器获取单个事件。
我第一次尝试使用HTTP/1.1↔ HTTP/2适配器类(InboundHttp2ToHttpAdapter
HttpToHttp2ConnectionHandler
),但有了这个组合,我只能在流关闭后获得完整的HttpResponse,而不是单个HttpContent对象。
接下来,我尝试设置一个管道,在其中发送单个传出的HTTP/2帧并侦听传入的HTTP/2帧,但似乎传出的HTTP/2帧编码器没有正确安装,因为我得到了以下异常:
Exception in thread "main" java.lang.RuntimeException: io.netty.handler.codec.UnsupportedMessageTypeException: io.netty.handler.codec.http2.DefaultHttp2HeadersFrame (expected: io.netty.buffer.ByteBuf)
at example.AsyncHttpClient.run(AsyncHttpClient.java:116)
at example.AsyncHttpClient.main(AsyncHttpClient.java:49)
Caused by: io.netty.handler.codec.UnsupportedMessageTypeException: io.netty.handler.codec.http2.DefaultHttp2HeadersFrame (expected: io.netty.buffer.ByteBuf)
at io.netty.handler.ssl.SslHandler.write(SslHandler.java:694)
at io.netty.channel.AbstractChannelHandlerContext.invokeWrite0(AbstractChannelHandlerContext.java:738)
at io.netty.channel.AbstractChannelHandlerContext.invokeWrite(AbstractChannelHandlerContext.java:730)
at io.netty.channel.AbstractChannelHandlerContext.write(AbstractChannelHandlerContext.java:816)
at io.netty.channel.AbstractChannelHandlerContext.write(AbstractChannelHandlerContext.java:723)
at io.netty.handler.codec.http2.Http2ConnectionHandler.write(Http2ConnectionHandler.java:498)
at io.netty.channel.AbstractChannelHandlerContext.invokeWrite0(AbstractChannelHandlerContext.java:738)
at io.netty.channel.AbstractChannelHandlerContext.invokeWrite(AbstractChannelHandlerContext.java:730)
at io.netty.channel.AbstractChannelHandlerContext.access$1900(AbstractChannelHandlerContext.java:38)
at io.netty.channel.AbstractChannelHandlerContext$AbstractWriteTask.write(AbstractChannelHandlerContext.java:1081)
at io.netty.channel.AbstractChannelHandlerContext$WriteAndFlushTask.write(AbstractChannelHandlerContext.java:1128)
at io.netty.channel.AbstractChannelHandlerContext$AbstractWriteTask.run(AbstractChannelHandlerContext.java:1070)
at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:163)
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:403)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:463)
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:858)
at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:138)
at java.lang.Thread.run(Thread.java:745)
关于我做错了什么有什么想法吗?我发现io.netty.handler.codec.http2包在如何组成类方面非常混乱。我尝试过使用Github上的Netty示例作为指南,但据我所知,大多数使用HTTP/1.1
完整源代码(也在github上):
package example;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http2.DefaultHttp2Connection;
import io.netty.handler.codec.http2.DefaultHttp2ConnectionDecoder;
import io.netty.handler.codec.http2.DefaultHttp2ConnectionEncoder;
import io.netty.handler.codec.http2.DefaultHttp2FrameReader;
import io.netty.handler.codec.http2.DefaultHttp2FrameWriter;
import io.netty.handler.codec.http2.DefaultHttp2Headers;
import io.netty.handler.codec.http2.DefaultHttp2HeadersFrame;
import io.netty.handler.codec.http2.Http2ConnectionHandler;
import io.netty.handler.codec.http2.Http2ConnectionHandlerBuilder;
import io.netty.handler.codec.http2.Http2Exception;
import io.netty.handler.codec.http2.Http2FrameAdapter;
import io.netty.handler.codec.http2.Http2Headers;
import io.netty.handler.codec.http2.Http2SecurityUtil;
import io.netty.handler.ssl.ApplicationProtocolConfig;
import io.netty.handler.ssl.ApplicationProtocolNames;
import io.netty.handler.ssl.OpenSsl;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.SslHandler;
import io.netty.handler.ssl.SslProvider;
import io.netty.handler.ssl.SupportedCipherSuiteFilter;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
import javax.net.ssl.SSLException;
import java.util.Collections;
import java.util.Map;
import static io.netty.channel.ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE;
public class AsyncHttpClient {
private final Channel channel;
public static void main(String[] args) throws InterruptedException {
final AsyncHttpClient client = new AsyncHttpClient("google.com", 443);
client.run("GET", "/", Collections.emptyMap());
Thread.sleep(10000);
}
AsyncHttpClient(String host, int port) throws InterruptedException {
final Bootstrap bootstrap = new Bootstrap()
.group(new NioEventLoopGroup())
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
final Http2FrameAdapter adapter = new Http2FrameAdapter() {
@Override
public void onHeadersRead(ChannelHandlerContext ctx, int streamId, Http2Headers headers, int padding, boolean endStream) throws Http2Exception {
System.out.println("onHeadersRead(ctx, streamId, headers, padding, endStream)");
super.onHeadersRead(ctx, streamId, headers, padding, endStream);
}
@Override
public void onHeadersRead(ChannelHandlerContext ctx, int streamId, Http2Headers headers, int streamDependency, short weight, boolean exclusive, int padding, boolean endStream) throws Http2Exception {
System.out.println("onHeadersRead(ctx, streamId, headers, streamDependency, weight, exclusive, padding, endStream)");
super.onHeadersRead(ctx, streamId, headers, streamDependency, weight, exclusive, padding, endStream);
}
@Override
public int onDataRead(ChannelHandlerContext ctx, int streamId, ByteBuf data, int padding, boolean endOfStream) throws Http2Exception {
System.out.println("onDataRead(ctx, streamId, data, padding, endOfStream)");
return super.onDataRead(ctx, streamId, data, padding, endOfStream);
}
};
final DefaultHttp2Connection connection = new DefaultHttp2Connection(false);
final DefaultHttp2FrameReader frameReader = new DefaultHttp2FrameReader();
final DefaultHttp2FrameWriter frameWriter = new DefaultHttp2FrameWriter();
final DefaultHttp2ConnectionEncoder encoder = new DefaultHttp2ConnectionEncoder(connection, frameWriter);
final DefaultHttp2ConnectionDecoder decoder = new DefaultHttp2ConnectionDecoder(connection, encoder, frameReader);
final Http2ConnectionHandler connectionHandler = new Http2ConnectionHandlerBuilder()
.codec(decoder, encoder)
.frameListener(adapter)
.build();
final ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(createSslHandler(ch));
pipeline.addLast(connectionHandler);
}
});
final ChannelFuture channelFuture = bootstrap.connect(host, port);
this.channel = channelFuture.sync().channel();
}
void run(String method, String path, Map<String, String> headerMap) {
final DefaultHttp2Headers headers = new DefaultHttp2Headers(true);
headers.scheme("https");
headers.method(method);
headers.path(path);
for (Map.Entry<String, String> header : headerMap.entrySet()) {
headers.add(header.getKey(), header.getValue());
}
final DefaultHttp2HeadersFrame frame = new DefaultHttp2HeadersFrame(headers, false);
try {
channel.writeAndFlush(frame)
.addListener(FIRE_EXCEPTION_ON_FAILURE)
.sync();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private SslHandler createSslHandler(SocketChannel channel) {
try {
final SslProvider provider = OpenSsl.isAlpnSupported() ? SslProvider.OPENSSL : SslProvider.JDK;
final SslContext sslCtx = SslContextBuilder.forClient().sslProvider(provider)
/* NOTE: the cipher filter may not include all ciphers required by the HTTP/2 specification.
* Please refer to the HTTP/2 specification for cipher requirements. */
.ciphers(Http2SecurityUtil.CIPHERS, SupportedCipherSuiteFilter.INSTANCE)
.trustManager(InsecureTrustManagerFactory.INSTANCE)
.applicationProtocolConfig(new ApplicationProtocolConfig(
ApplicationProtocolConfig.Protocol.ALPN,
// NO_ADVERTISE is currently the only mode supported by both OpenSsl and JDK providers.
ApplicationProtocolConfig.SelectorFailureBehavior.NO_ADVERTISE,
// ACCEPT is currently the only mode supported by both OpenSsl and JDK providers.
ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT,
ApplicationProtocolNames.HTTP_2))
.build();
return sslCtx.newHandler(channel.alloc());
} catch (SSLException e) {
throw new RuntimeException(e);
}
}
}
如果要使用Http2*帧对象,则需要使用Http2FrameCodec或Http2MultiplexCodec,而不需要使用Http2ConnectionHandler。有关如何使用它的详细信息,请参阅netty示例和单元测试。
客户端配置项设置示例 lookoutConfig.setProperty(LookoutConfig.LOOKOUT_AGENT_HOST_ADDRESS,"127.0.0.1"); 客户端配置项说明 配置项 对应 SpringBoot 配置项 默认配置值 说明 lookout.enable com.alipay.sofa.lookout.enable true 功能开关,默认是 true。如
我有一些构建工件,其中包含一些调试信息,我希望在构建摘要中显示这些信息。然而,我看到的唯一获取工件的API是一个zip文件。如果您转到工件屏幕并浏览工件,然后复制下载URL,您将得到一个API,如下所示: https://{帐户}/_ API/资源/容器/{容器}?itemPath = {文件名} 但是,我似乎找不到REST客户端API来在扩展中的ts脚本中使用此功能。 对如何从中获取实际文件有什
是否有一种方法可以将“配置客户机”和访问文件定义为configClient.getResource(),而不是从url获取
当我运行Spring Cloud Config Client项目config-client时,我发现了以下错误: 启动ApplicationContext时出错。若要显示自动配置报告,请在启用“debug”的情况下重新运行应用程序。2018-02-09 10:31:10.923错误13933--[main]O.S.Boot.SpringApplication:应用程序启动失败 显然,配置服务器是错
问题内容: 我不完全了解如何获取远程用户IP地址。 假设我有一个简单的请求路由,例如: 以上方法是正确的以获得真实用户IP地址还是有更好的方法?代理呢? 问题答案: 如果您是在像NGiNX这样的代理服务器上运行或者只有什么,那么您应该检查’x-forwarded-for’: 如果代理不是“您的”,那么我将不信任“ x-forward-for”标头,因为它可能是被欺骗的。
我不完全理解如何获得远程用户IP地址。 假设我有一个简单的请求路由,例如: 上面的方法是正确的,还是有更好的方法来获得真正的用户IP地址?代理呢?