如果我希望使用System.Net.HttpClient提交http get请求,似乎没有api添加参数,这是正确的吗?
是否有任何简单的api可用于构建查询字符串,该字符串不涉及构建名称值集合和url编码那些然后最终连接它们?我希望使用类似RestSharp的api(即AddParameter(..))
Dar*_*rov 272
如果我希望使用System.Net.HttpClient提交http get请求,似乎没有api添加参数,这是正确的吗?
是.
是否有任何简单的api可用于构建查询字符串,该字符串不涉及构建名称值集合和url编码那些然后最终连接它们?
当然:
var query = HttpUtility.ParseQueryString(string.Empty);
query["foo"] = "bar<>&-baz";
query["bar"] = "bazinga";
string queryString = query.ToString();
Run Code Online (Sandbox Code Playgroud)
会给你预期的结果:
foo=bar%3c%3e%26-baz&bar=bazinga
Run Code Online (Sandbox Code Playgroud)
您可能还会发现该UriBuilder课程很有用:
var builder = new UriBuilder("http://example.com");
builder.Port = -1;
var query = HttpUtility.ParseQueryString(builder.Query);
query["foo"] = "bar<>&-baz";
query["bar"] = "bazinga";
builder.Query = query.ToString();
string url = builder.ToString();
Run Code Online (Sandbox Code Playgroud)
会给你预期的结果:
http://example.com/?foo=bar%3c%3e%26-baz&bar=bazinga
Run Code Online (Sandbox Code Playgroud)
你可以安全地提供给你的HttpClient.GetAsync方法.
Ros*_*tov 76
对于那些谁不想要包括System.Web在还没有使用它的项目,你可以使用FormUrlEncodedContent从System.Net.Http做类似如下:
string query;
using(var content = new FormUrlEncodedContent(new KeyValuePair<string, string>[]{
new KeyValuePair<string, string>("ham", "Glazed?"),
new KeyValuePair<string, string>("x-men", "Wolverine + Logan"),
new KeyValuePair<string, string>("Time", DateTime.UtcNow.ToString()),
})) {
query = content.ReadAsStringAsync().Result;
}
Run Code Online (Sandbox Code Playgroud)
string query;
using(var content = new FormUrlEncodedContent(new Dictionary<string, string>()
{
{ "ham", "Glaced?"},
{ "x-men", "Wolverine + Logan"},
{ "Time", DateTime.UtcNow.ToString() },
})) {
query = content.ReadAsStringAsync().Result;
}
Run Code Online (Sandbox Code Playgroud)
ill*_*ant 33
TL; DR:不要使用可接受的版本,因为它在处理unicode字符方面完全被破坏,并且从不使用内部API
我实际上发现了接受的解决方案奇怪的双重编码问题:
因此,如果您正在处理需要编码的字符,则接受的解决方案会导致双重编码:
NameValueCollection索引器自动编码的(这使用UrlEncodeUnicode,而不是常规预期UrlEncode(!))uriBuilder.Uri它时会创建一个新的Uriusing构造函数,它会再次编码(正常的url编码)uriBuilder.ToString()(尽管这会返回正确的Uri哪个IMO至少是不一致,可能是一个错误,但这是另一个问题)然后使用HttpClient方法接受字符串 - 客户端仍然会创建Uri你传递的字符串,如下所示:new Uri(uri, UriKind.RelativeOrAbsolute)小但完全重现:
var builder = new UriBuilder
{
Scheme = Uri.UriSchemeHttps,
Port = -1,
Host = "127.0.0.1",
Path = "app"
};
NameValueCollection query = HttpUtility.ParseQueryString(builder.Query);
query["cyrillic"] = "????????";
builder.Query = query.ToString();
Console.WriteLine(builder.Query); //query with cyrillic stuff UrlEncodedUnicode, and that's not what you want
var uri = builder.Uri; // creates new Uri using constructor which does encode and messes cyrillic parameter even more
Console.WriteLine(uri);
// this is still wrong:
var stringUri = builder.ToString(); // returns more 'correct' (still `UrlEncodedUnicode`, but at least once, not twice)
new HttpClient().GetStringAsync(stringUri); // this creates Uri object out of 'stringUri' so we still end up sending double encoded cyrillic text to server. Ouch!
Run Code Online (Sandbox Code Playgroud)
输出:
?cyrillic=%u043a%u0438%u0440%u0438%u043b%u0438%u0446%u044f
https://127.0.0.1/app?cyrillic=%25u043a%25u0438%25u0440%25u0438%25u043b%25u0438%25u0446%25u044f
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,无论您执行uribuilder.ToString()+ httpClient.GetStringAsync(string)或uriBuilder.Uri+,httpClient.GetStringAsync(Uri)您最终都会发送双重编码参数
固定的例子可能是:
var uri = new Uri(builder.ToString(), dontEscape: true);
new HttpClient().GetStringAsync(uri);
Run Code Online (Sandbox Code Playgroud)
但是这使用了过时的 Uri构造函数
PS on我最新的Windows on Windows Server,Uri构造函数与bool doc评论说"过时,dontEscape总是假的",但实际上按预期工作(跳过转义)
所以它看起来像另一个bug ...
即使这是完全错误的 - 它将UrlEncodedUnicode发送到服务器,而不仅仅是UrlEncoded服务器所期望的
更新:一件事是,NameValueCollection中实际上做UrlEncodeUnicode,这是不应该再被使用,并定期url.encode /解码兼容(见的NameValueCollection到URL查询?).
所以底线是:永远不要使用这个hack,NameValueCollection query = HttpUtility.ParseQueryString(builder.Query);因为它会弄乱你的unicode查询参数.只需手动构建查询并将其分配给UriBuilder.Query必要的编码,然后使用Uri UriBuilder.Uri.
通过使用不应该像这样使用的代码来伤害自己的主要例子
Mag*_*agu 29
在ASP.NET Core项目中,您可以使用QueryHelpers类.
// using Microsoft.AspNetCore.WebUtilities;
var query = new Dictionary<string, string>
{
["foo"] = "bar",
["foo2"] = "bar2",
// ...
};
var response = await client.GetAsync(QueryHelpers.AddQueryString("/api/", query));
Run Code Online (Sandbox Code Playgroud)
Tod*_*ier 22
您可能想查看Flurl [披露:我是作者],一个流畅的URL构建器,带有可选的伴随库,可将其扩展为一个完整的REST客户端.
var result = await "https://api.com"
// basic URL building:
.AppendPathSegment("endpoint")
.SetQueryParams(new {
api_key = ConfigurationManager.AppSettings["SomeApiKey"],
max_results = 20,
q = "Don't worry, I'll get encoded!"
})
.SetQueryParams(myDictionary)
.SetQueryParam("q", "overwrite q!")
// extensions provided by Flurl.Http:
.WithOAuthBearerToken("token")
.GetJsonAsync<TResult>();
Run Code Online (Sandbox Code Playgroud)
查看文档以获取更多详细信息.NuGet提供完整的软件包:
PM> Install-Package Flurl.Http
或者只是独立的URL构建器:
PM> Install-Package Flurl
与 Rostov 的帖子相同,如果您不想System.Web在项目中包含对的引用,您可以使用FormDataCollectionfromSystem.Net.Http.Formatting并执行如下操作:
System.Net.Http.Formatting.FormDataCollectionvar parameters = new Dictionary<string, string>()
{
{ "ham", "Glaced?" },
{ "x-men", "Wolverine + Logan" },
{ "Time", DateTime.UtcNow.ToString() },
};
var query = new FormDataCollection(parameters).ReadAsNameValueCollection().ToString();
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
144745 次 |
| 最近记录: |