超级客户端无法在 IPv6 本地主机上查找服务器 运行 的地址信息
hyper client cannot lookup address information for server running on IPv6 localhost
我有一个简单的 HTTP 服务器,它在端口 3005 上使用 Router 和 Iron。它没有做任何令人兴奋的事情。我相信它只是回应了请求,但细节并不重要。
我也做了一个简单的客户端,使用 hyper 的客户端模块向服务器发送请求。
每当我 运行 IPv4 localhost
上的服务器时,我都没有遇到任何问题。我可以通过我的客户和 curl 查询它。如果我在我的 IPv6 localhost
上启动服务器(我使用的是缩短版本 ::1
),我只能使用 curl 访问服务器。
这表明服务器 运行 正在正常响应,但我的超级 Client
代码访问它失败,报告:
Err(Io(Error { repr: Custom(Custom { kind: Other, error: StringError("failed to lookup address information: Name or service not known") }) }))
thread 'main' panicked at 'called Result::unwrap()
on an Err
value: Io(Error { repr: Custom(Custom { kind: Other, error: StringError("failed to lookup address information: Name or service not known") }) })', /checkout/src/libcore/result.rs:860
我用来发送POST请求的代码如下:
let addr = "http://[::1]:3005/message";
let mut res = self.client.post(addr).body(s.as_str()).send().unwrap();
其中 s
是我发送的一些负载。
我也尝试了扩展的 IPv6 地址 ([0:0:0:0:0:0:0:1]
),但我得到了同样的错误。
我还尝试了不带括号的缩短和扩展 IPv6 地址。我得到扩展地址 "invalid port -" 和缩短地址 "Empty Host"。
要重现此行为,您可以使用这些小示例(取消注释行以接收错误):
服务器
extern crate iron;
use iron::prelude::*;
use iron::status;
fn hello_world(_: &mut Request) -> IronResult<Response> {
println!("Recvd a request");
Ok(Response::with((status::Ok, "Hello World!")))
}
fn main() {
let port = 3000;
//let addr = format!("{}:{}", "[::1]", port);
let addr = format!("{}:{}", "localhost", port);
println!("Server opened on {}", addr);
Iron::new(hello_world).http(addr).unwrap();
}
客户端
// hyper 0.10.13
extern crate hyper;
use hyper::*;
use std::io::Read;
fn main() {
let client = Client::new();
//let mut res = client.get("http://[::1]:3000/").send().unwrap();
let mut res = client.get("http://localhost:3000/").send().unwrap();
let mut s = String::new();
res.read_to_string(&mut s).unwrap();
println!("response contained: {}", s);
}
ClientV2
// For people that want to try with hyper 0.11.X
extern crate futures;
extern crate hyper;
extern crate tokio_core;
use std::io::{self, Write};
use futures::{Future, Stream};
use hyper::Client;
use tokio_core::reactor::Core;
fn main() {
let mut core = Core::new().unwrap();
let client = Client::new(&core.handle());
let uri = "http://[::1]:3000/".parse().unwrap();
let work = client.get(uri).and_then(|res| {
println!("Response: {}", res.status());
res.body().for_each(|chunk| {
io::stdout()
.write_all(&chunk)
.map(|_| ())
.map_err(From::from)
})
});
core.run(work).unwrap();
}
注1:
您需要 hyper 0.10.X 才能获得此代码 运行ning。就我而言,我使用的是 0.10.13
注2:
我正在发送没有负载的 GET 请求,以便抽象出不相关的功能位。
注3:
hyper 0.10.X 和 hyper 0.11.X 似乎以不同方式处理 IPv6 服务器。 Hyper 0.10.X 给出了上述错误,而 0.11.X 给出了响应代码 400 Bad Request。
IPv6 支持似乎是 an issue with the previous and current versions of hyperium/hyper (<=0.11.23)
开发人员建议为使用 hyper 0 的客户端使用 Reqwest crate。11.X,但由于 Reqwest 建立在 hyper 之上,因此结果将是相同的。
到目前为止我找到的解决方案是使用 cURL 的 Rust 绑定,因为 cURL 似乎足够健壮。这是我编写客户端的代码,该客户端将简单的 GET 请求发送到 IPv6 服务器地址。
客户端
extern crate curl;
use std::io::{stdout, Write};
use curl::easy::Easy;
fn main() {
let mut easy = Easy::new();
easy.url("https://[::1]:3000").unwrap();
easy.write_function(|data| {
stdout().write_all(data).unwrap();
Ok(data.len())
}).unwrap();
easy.perform().unwrap();
}
这不是最漂亮的解决方案,因为它使用内置于 C 中的库,这是一种不安全的语言,但在出现更好的替代方案之前,它是一个很好的解决方法。
我有一个简单的 HTTP 服务器,它在端口 3005 上使用 Router 和 Iron。它没有做任何令人兴奋的事情。我相信它只是回应了请求,但细节并不重要。
我也做了一个简单的客户端,使用 hyper 的客户端模块向服务器发送请求。
每当我 运行 IPv4 localhost
上的服务器时,我都没有遇到任何问题。我可以通过我的客户和 curl 查询它。如果我在我的 IPv6 localhost
上启动服务器(我使用的是缩短版本 ::1
),我只能使用 curl 访问服务器。
这表明服务器 运行 正在正常响应,但我的超级 Client
代码访问它失败,报告:
Err(Io(Error { repr: Custom(Custom { kind: Other, error: StringError("failed to lookup address information: Name or service not known") }) })) thread 'main' panicked at 'called
Result::unwrap()
on anErr
value: Io(Error { repr: Custom(Custom { kind: Other, error: StringError("failed to lookup address information: Name or service not known") }) })', /checkout/src/libcore/result.rs:860
我用来发送POST请求的代码如下:
let addr = "http://[::1]:3005/message";
let mut res = self.client.post(addr).body(s.as_str()).send().unwrap();
其中 s
是我发送的一些负载。
我也尝试了扩展的 IPv6 地址 ([0:0:0:0:0:0:0:1]
),但我得到了同样的错误。
我还尝试了不带括号的缩短和扩展 IPv6 地址。我得到扩展地址 "invalid port -" 和缩短地址 "Empty Host"。
要重现此行为,您可以使用这些小示例(取消注释行以接收错误):
服务器
extern crate iron;
use iron::prelude::*;
use iron::status;
fn hello_world(_: &mut Request) -> IronResult<Response> {
println!("Recvd a request");
Ok(Response::with((status::Ok, "Hello World!")))
}
fn main() {
let port = 3000;
//let addr = format!("{}:{}", "[::1]", port);
let addr = format!("{}:{}", "localhost", port);
println!("Server opened on {}", addr);
Iron::new(hello_world).http(addr).unwrap();
}
客户端
// hyper 0.10.13
extern crate hyper;
use hyper::*;
use std::io::Read;
fn main() {
let client = Client::new();
//let mut res = client.get("http://[::1]:3000/").send().unwrap();
let mut res = client.get("http://localhost:3000/").send().unwrap();
let mut s = String::new();
res.read_to_string(&mut s).unwrap();
println!("response contained: {}", s);
}
ClientV2
// For people that want to try with hyper 0.11.X
extern crate futures;
extern crate hyper;
extern crate tokio_core;
use std::io::{self, Write};
use futures::{Future, Stream};
use hyper::Client;
use tokio_core::reactor::Core;
fn main() {
let mut core = Core::new().unwrap();
let client = Client::new(&core.handle());
let uri = "http://[::1]:3000/".parse().unwrap();
let work = client.get(uri).and_then(|res| {
println!("Response: {}", res.status());
res.body().for_each(|chunk| {
io::stdout()
.write_all(&chunk)
.map(|_| ())
.map_err(From::from)
})
});
core.run(work).unwrap();
}
注1:
您需要 hyper 0.10.X 才能获得此代码 运行ning。就我而言,我使用的是 0.10.13
注2:
我正在发送没有负载的 GET 请求,以便抽象出不相关的功能位。
注3:
hyper 0.10.X 和 hyper 0.11.X 似乎以不同方式处理 IPv6 服务器。 Hyper 0.10.X 给出了上述错误,而 0.11.X 给出了响应代码 400 Bad Request。
IPv6 支持似乎是 an issue with the previous and current versions of hyperium/hyper (<=0.11.23)
开发人员建议为使用 hyper 0 的客户端使用 Reqwest crate。11.X,但由于 Reqwest 建立在 hyper 之上,因此结果将是相同的。
到目前为止我找到的解决方案是使用 cURL 的 Rust 绑定,因为 cURL 似乎足够健壮。这是我编写客户端的代码,该客户端将简单的 GET 请求发送到 IPv6 服务器地址。
客户端
extern crate curl;
use std::io::{stdout, Write};
use curl::easy::Easy;
fn main() {
let mut easy = Easy::new();
easy.url("https://[::1]:3000").unwrap();
easy.write_function(|data| {
stdout().write_all(data).unwrap();
Ok(data.len())
}).unwrap();
easy.perform().unwrap();
}
这不是最漂亮的解决方案,因为它使用内置于 C 中的库,这是一种不安全的语言,但在出现更好的替代方案之前,它是一个很好的解决方法。