programing

시스템에 대한 쿼리 문자열을 빌드합니다.Net.HttpClient 가져오기

projobs 2023. 5. 14. 23:29
반응형

시스템에 대한 쿼리 문자열을 빌드합니다.Net.HttpClient 가져오기

만약 내가 http를 제출하고 싶다면 시스템을 사용하여 요청을 받습니다.Net.HttpClient에는 매개 변수를 추가할 수 있는 api가 없는 것 같습니다. 맞나요?

이름 값 컬렉션을 빌드하고 URL을 인코딩한 다음 최종적으로 연결하는 것을 포함하지 않는 쿼리 문자열을 빌드할 수 있는 간단한 api가 있습니까?RestSharp의 api(예: Add Parameter(...))와 같은 것을 사용하고 싶었습니다.

만약 내가 http를 제출하고 싶다면 시스템을 사용하여 요청을 받습니다.Net.HttpClient에는 매개 변수를 추가할 수 있는 api가 없는 것 같습니다. 맞나요?

네.

이름 값 컬렉션을 빌드하고 URL을 인코딩한 다음 최종적으로 연결하는 것을 포함하지 않는 쿼리 문자열을 빌드할 수 있는 간단한 api가 있습니까?

물론:

var query = HttpUtility.ParseQueryString(string.Empty);
query["foo"] = "bar<>&-baz";
query["bar"] = "bazinga";
string queryString = query.ToString();

예상 결과를 제공합니다.

foo=bar%3c%3e%26-baz&bar=bazinga

당은또수있다니습을찾한신▁the를 찾을 수도 있습니다.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();

예상 결과를 제공합니다.

http://example.com/?foo=bar%3c%3e%26-baz&bar=bazinga

당신이 당신에게 안전하게 공급할 수 있는 것 이상.HttpClient.GetAsync방법.

포함하지 않으려는 사용자를 위해System.Web아직 사용하지 않는 프로젝트에서 사용할 수 있습니다.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;
}

사전판

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;
}

ASP. 프로젝트에서는 NET Core할 수 있습니다.QueryHelpers 스사용가에서 가능Microsoft.AspNetCore.WebUtilitiesASP의 네임스페이스입니다.NET Core 또는 .다른 소비자를 위한 NET Standard 2.0 NuGet 패키지:

// using Microsoft.AspNetCore.WebUtilities;
var query = new Dictionary<string, string>
{
    ["foo"] = "bar",
    ["foo2"] = "bar2",
    // ...
};

var response = await client.GetAsync(QueryHelpers.AddQueryString("/api/", query));

TL;DR: Unicode 문자 처리와 관련하여 완전히 중단되었으므로 승인된 버전을 사용하지 않으며, 내부 API를 사용하지 않습니다.

저는 실제로 승인된 솔루션에서 이상한 이중 인코딩 문제를 발견했습니다.

따라서 인코딩이 필요한 문자를 처리하는 경우 수락된 솔루션은 이중 인코딩으로 이어집니다.

  • 는 쿼리 매변 다을사자용인동다니코됩딩으로여하음을 으로 인코딩됩니다.NameValueCollection인덱서(및 이 기능은 일반적으로 예상되지 않음(!)을 사용합니다).
  • 그럼을 부를 때 당이전화할때신때할▁then전화,이▁you▁when.uriBuilder.Uri그것은 새로운 것을 만듭니다.Uri한 번 더 인코딩하는 생성자 사용(일반 URL 인코딩)
  • (이것이 정확하게 반환되더라도) 그렇게 해서는 피할없습니다.Uri일 수도 입니다.) IMO를 사용합니다.HttpClient문자열을 수락하는 메서드 - 클라이언트는 여전히 다음과 같이 전달된 문자열을 만듭니다.

작지만 완전한 비난:

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!

출력:

?cyrillic=%u043a%u0438%u0440%u0438%u043b%u0438%u0446%u044f

https://127.0.0.1/app?cyrillic=%25u043a%25u0438%25u0440%25u0438%25u043b%25u0438%25u0446%25u044f

처럼, 이 시는바같이와해를 , 당이그렇도게신보해▁as도▁no그게렇,▁if이▁do.uribuilder.ToString()+httpClient.GetStringAsync(string)또는uriBuilder.Uri+httpClient.GetStringAsync(Uri)은 결국 된 파라미터를 .

고정된 예는 다음과 같습니다.

var uri = new Uri(builder.ToString(), dontEscape: true);
new HttpClient().GetStringAsync(uri);

하지만 이것은 쓸모없는 것을 사용합니다. Uri

최근 .. . . . . . . . . . . . . . . . . , 윈도즈서의 NET,Uri를 가진 는 " 거짓이다"라고말하지만

다른 벌레처럼 보이는군요

그리고 이것조차도 명백히 잘못된 것입니다 - 그것은 UrlEncoded를 보냅니다.서버가 기대하는 UrlEncoded가 아닌 서버에 대한 유니코드

업데이트: 한 가지 더, NameValueCollection이 실제로 UrlEncode를 수행합니다.유니코드. 더 이상 사용할 수 없으며 일반 url.encode/decode와 호환되지 않습니다(URL 쿼리에 대한 NameValueCollection? 참조).

그래서 결론은: 유니코드 쿼리 매개 변수를 엉망으로 만들 수 있으므로 이 해킹을 사용하지 말라는 것입니다.수동으로 쿼리를 빌드하고 할당하기만 하면 됩니다.UriBuilder.Query URI를 사용하여 URI를 .UriBuilder.Uri.

이렇게 사용해서는 안 되는 코드를 사용하여 자신을 다치게 한 대표적인 예

Flurl [공개:저는 완전한 REST 클라이언트로 확장하는 선택적 컴패니언 lib를 갖춘 유창한 URL 빌더인 저자입니다.

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>();

자세한 내용은 문서를 참조하십시오.전체 패키지는 NuGet에서 사용할 수 있습니다.

PM> Install-Package Flurl.Http

또는 독립 실행형 URL 작성기만 사용할 수 있습니다.

PM> Install-Package Flurl

로스토프의 게시물과 같은 맥락에서, 만약 당신이 언급을 포함하고 싶지 않다면.System.Web로젝트사수있습다니용할서를 사용할 수 .FormDataCollectionSystem.Net.Http.Formatting다음과 같은 작업을 수행합니다.

사용

var parameters = new Dictionary<string, string>()
{
    { "ham", "Glaced?" },
    { "x-men", "Wolverine + Logan" },
    { "Time", DateTime.UtcNow.ToString() },
}; 
var query = new FormDataCollection(parameters).ReadAsNameValueCollection().ToString();

이 몇 시간을 재사용해야 하기 때문에 쿼리 문자열이 어떻게 구성되어 있는지 추상화하는 데 도움이 되는 이 클래스를 생각해 냈습니다.

public class UriBuilderExt
{
    private NameValueCollection collection;
    private UriBuilder builder;

    public UriBuilderExt(string uri)
    {
        builder = new UriBuilder(uri);
        collection = System.Web.HttpUtility.ParseQueryString(string.Empty);
    }

    public void AddParameter(string key, string value) {
        collection.Add(key, value);
    }

    public Uri Uri{
        get
        {
            builder.Query = collection.ToString();
            return builder.Uri;
        }
    }

}

사용은 다음과 같은 방식으로 단순화됩니다.

var builder = new UriBuilderExt("http://example.com/");
builder.AddParameter("foo", "bar<>&-baz");
builder.AddParameter("bar", "second");
var uri = builder.Uri;

http://example.com/ ?foo=bar%3c%3e%26-baz&bar=second를 반환합니다.

수락된 답변의 좋은 부분입니다. URIBuilder를 사용하도록 수정되었습니다.HttpUtility 대신 Uri.ParseQueryString().ParseQueryString():

var builder = new UriBuilder("http://example.com");
var query = builder.Uri.ParseQueryString();
query["foo"] = "bar<>&-baz";
query["bar"] = "bazinga";
builder.Query = query.ToString();
string url = builder.ToString();

Darin은 흥미롭고 현명한 해결책을 제시했으며, 여기 또 다른 옵션이 있을 수 있는 것이 있습니다.

public class ParameterCollection
{
    private Dictionary<string, string> _parms = new Dictionary<string, string>();

    public void Add(string key, string val)
    {
        if (_parms.ContainsKey(key))
        {
            throw new InvalidOperationException(string.Format("The key {0} already exists.", key));
        }
        _parms.Add(key, val);
    }

    public override string ToString()
    {
        var server = HttpContext.Current.Server;
        var sb = new StringBuilder();
        foreach (var kvp in _parms)
        {
            if (sb.Length > 0) { sb.Append("&"); }
            sb.AppendFormat("{0}={1}",
                server.UrlEncode(kvp.Key),
                server.UrlEncode(kvp.Value));
        }
        return sb.ToString();
    }
}

따라서 사용 시 다음과 같은 작업을 수행할 수 있습니다.

var parms = new ParameterCollection();
parms.Add("key", "value");

var url = ...
url += "?" + parms;

제가 개발 중인 RFC 6570 URI Template 라이브러리에서 이 작업을 수행할 수 있습니다.모든 인코딩은 해당 RFC에 따라 처리됩니다.이 문서를 작성할 때 베타 릴리스를 사용할 수 있지만 안정적인 1.0 릴리스로 간주되지 않는 유일한 이유는 문서가 제 기대를 완전히 충족하지 못하기 때문입니다(#17, #18, #32, #43 문제 참조).

쿼리 문자열을 단독으로 작성할 수 있습니다.

UriTemplate template = new UriTemplate("{?params*}");
var parameters = new Dictionary<string, string>
  {
    { "param1", "value1" },
    { "param2", "value2" },
  };
Uri relativeUri = template.BindByName(parameters);

또는 완전한 URI를 구축할 수 있습니다.

UriTemplate template = new UriTemplate("path/to/item{?params*}");
var parameters = new Dictionary<string, string>
  {
    { "param1", "value1" },
    { "param2", "value2" },
  };
Uri baseAddress = new Uri("http://www.example.com");
Uri relativeUri = template.BindByName(baseAddress, parameters);

또는 단순히 내 URI 확장자를 사용하는 것.

코드

public static Uri AttachParameters(this Uri uri, NameValueCollection parameters)
{
    var stringBuilder = new StringBuilder();
    string str = "?";
    for (int index = 0; index < parameters.Count; ++index)
    {
        stringBuilder.Append(str + parameters.AllKeys[index] + "=" + parameters[index]);
        str = "&";
    }
    return new Uri(uri + stringBuilder.ToString());
}

사용.

Uri uri = new Uri("http://www.example.com/index.php").AttachParameters(new NameValueCollection
                                                                           {
                                                                               {"Bill", "Gates"},
                                                                               {"Steve", "Jobs"}
                                                                           });

결과

http://www.example.com/index.php?Bill=Gates&Steve=Jobs

taras.roshko의 답변에 설명된 이중 인코딩 문제를 방지하고 쿼리 매개 변수로 쉽게 작업할 수 있도록 하려면 다음을 사용할 수 있습니다.uriBuilder.Uri.ParseQueryString()대신에HttpUtility.ParseQueryString().

"다린 디미트로프" 덕분에, 이것은 확장 방법입니다.

 public static partial class Ext
{
    public static Uri GetUriWithparameters(this Uri uri,Dictionary<string,string> queryParams = null,int port = -1)
    {
        var builder = new UriBuilder(uri);
        builder.Port = port;
        if(null != queryParams && 0 < queryParams.Count)
        {
            var query = HttpUtility.ParseQueryString(builder.Query);
            foreach(var item in queryParams)
            {
                query[item.Key] = item.Value;
            }
            builder.Query = query.ToString();
        }
        return builder.Uri;
    }

    public static string GetUriWithparameters(string uri,Dictionary<string,string> queryParams = null,int port = -1)
    {
        var builder = new UriBuilder(uri);
        builder.Port = port;
        if(null != queryParams && 0 < queryParams.Count)
        {
            var query = HttpUtility.ParseQueryString(builder.Query);
            foreach(var item in queryParams)
            {
                query[item.Key] = item.Value;
            }
            builder.Query = query.ToString();
        }
        return builder.Uri.ToString();
    }
}
HttpClient client = new HttpClient();
var uri = Environment.GetEnvironmentVariable("URL of Api");
                
var requesturi = QueryHelpers.AddQueryString(uri, "parameter_name",parameter_value);
client.BaseAddress = new Uri(requesturi);

그런 다음 요청 헤더를 추가할 수 있습니다. 예:

client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Add("x-api-key", secretValue);

응답 구문(예:

HttpResponseMessage response = client.GetAsync(requesturi).Result;

그것이 당신에게 효과가 있기를 바랍니다.

제 대답은 세계적으로 받아들여진/다른 대답과 다르지 않습니다.나는 단지 가변적인 수의 매개 변수를 사용하는 URI 유형에 대한 확장 방법을 만들려고 했습니다.

public static class UriExtensions
{
    public static Uri AddParameter(this Uri url, params (string Name, string Value)[] @params)
    {
        if (!@params.Any())
        {
            return url;
        }

        UriBuilder uriBuilder = new(url);

        NameValueCollection query = HttpUtility.ParseQueryString(uriBuilder.Query);

        foreach (var param in @params)
        {
            query[param.Name] = param.Value.Trim();
        }

        uriBuilder.Query = query.ToString();

        return uriBuilder.Uri;
    }
}

사용 예:

var uri = new Uri("http://someuri.com")
    .AddParameter(
       ("p1.name", "p1.value"),
       ("p2.name", "p2.value"),
       ("p3.name", "p3.value"));

사전을 QueryStringFormat으로 변환하는 확장 메서드를 만드는 것보다 더 좋은 솔루션을 찾을 수 없었습니다.Waleed A.K.가 제안한 해결책도 좋습니다.

내 솔루션을 따릅니다.

확장 메서드를 만듭니다.

public static class DictionaryExt
{
    public static string ToQueryString<TKey, TValue>(this Dictionary<TKey, TValue> dictionary)
    {
        return ToQueryString<TKey, TValue>(dictionary, "?");
    }

    public static string ToQueryString<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, string startupDelimiter)
    {
        string result = string.Empty;
        foreach (var item in dictionary)
        {
            if (string.IsNullOrEmpty(result))
                result += startupDelimiter; // "?";
            else
                result += "&";

            result += string.Format("{0}={1}", item.Key, item.Value);
        }
        return result;
    }
}

그리고 그들:

var param = new Dictionary<string, string>
          {
            { "param1", "value1" },
            { "param2", "value2" },
          };
param.ToQueryString(); //By default will add (?) question mark at begining
//"?param1=value1&param2=value2"
param.ToQueryString("&"); //Will add (&)
//"&param1=value1&param2=value2"
param.ToQueryString(""); //Won't add anything
//"param1=value1&param2=value2"

언급URL : https://stackoverflow.com/questions/17096201/build-query-string-for-system-net-httpclient-get

반응형