【问题标题】:Rewriting a Java HttpURLConnection method using C# HttpClient使用 C# HttpClient 重写 Java HttpURLConnection 方法
【发布时间】:2021-09-27 08:13:19
【问题描述】:

我有一个使用 java.net.HttpURLConnection 的有效 Java 方法,我应该使用 .NET HttpClient 在 C# 中重新实现它。

Java 方法:

public static String getMyThingAPIToken() throws IOException{
    URL apiURL = new URL("https://myThingAPI/token");
    HttpURLConnection apiConnection = (HttpURLConnection) apiURL.openConnection();
    apiConnection.setRequestMethod("POST");
    apiConnection.setDoOutput(true);
    String apiBodyString = "myThingAPI login id and secret key";
    byte[] apiBody = apiBodyString.getBytes(StandardCharsets.UTF_8);

    OutputStream apiBodyStream = apiConnection.getOutputStream();
    apiBodyStream.write(apiBody);
    
    StringBuffer apiResponseBuffer;
    try (BufferedReader in = new BufferedReader(new InputStreamReader(apiConnection.getInputStream()))){
        String inputline;
        apiResponseBuffer = new StringBuffer();
        while((inputline = in.readLine()) != null) {
            apiResponseBuffer.append(inputline);
        }
    }
}

到目前为止,我的 C# 如下所示,您会注意到我的这种早期实现形式不会解释响应。它也没有令牌字符串所需的字符串返回类型。

这是因为当我测试它时,响应有: 状态码:400 原因短语:'错误请求'

所以我的 apiBody 字节数组中的某些内容或 PostAsync 的使用必须与 Java 方法所做的不同,但我无法弄清楚它可能是什么。

public async static Task<HttpResponseMessage> getMyThingAPIToken(HttpClient client)
{
    var apiURI = new Uri("https://myThingAPI/token");
    string apiBodystring = "myThingAPI login id and secret key";
    byte[] apiBody = System.Text.Encoding.UTF8.GetBytes(apiBodystring);
    var response = await client.PostAsync(apiURI, new ByteArrayContent(apiBody));
    return response;
}

【问题讨论】:

  • 你试过StringContent吗? (只是一枪成蓝)
  • “但我无法弄清楚它可能是什么” - 使用 FIddler 或 WireShark 等工具可能有助于查看在线请求中的差异。跨度>
  • @Fildor 是的,结果相同 - 似乎 API 要求它是一个字节 []。不过谢谢,我会试试你提到的工具
  • 没有一个例子明确设置内容类型,所以这也可能是不同的。但确实如前所述 - 只需在两种情况下都使用该工具并检查标题。
  • @trajekolus 没有 API 要求任何东西都是 byte[],因为 一切都是字节。文本是解释这些字节的一种方式。 UTF8 是一种将文本编码为字节的特定方式。如果您使用StringContent,您会说您将发送一个字符串,HttpClient 将使用指定的编码将其转换为字节。你在这里做的是StringContent 会做的事情

标签: c# dotnet-httpclient


【解决方案1】:

Java 代码没有指定类型,这意味着by default 请求使用application/x-www-form-urlencoded。这用于 FORM POST 请求。

另一方面,ByteArrayContent 的默认内容类型是 application/octet-stream,而 StringContent 的默认内容类型是 text/plain。 FORM 内容通过FormUrlEncoodedContent 类使用,该类可以接受任何Dictionary&lt;string,string&gt; 作为有效负载。

问题中的输入不是 x-www-form-urlencoded 形式,因此要么不是真实内容,要么 API 滥用了内容类型。

假设 API 接受正确的 x-www-form-urlencoded 内容,以下应该可以工作:

var data=new Dictionary<string,string>{
    ["login"]=....,
    ["secret"]=.....,
    ["someOtherField"]=....
};
var content= new FormUrlEncodedContent(data);
var response=await client.PostAsync(apiURI,content);

要使用application/x-www-form-urlencoded 发送任何文本,我们需要在StringContent's constructor 中指定内容类型:

var contentType="application/x-www-form-urlencoded";
var content= new StringContent(apiBodyString, Encoding.UTF8,contentType);
var response=await client.PostAsync(apiURI,content);

【讨论】:

    【解决方案2】:

    您可以尝试使用以下代码吗:

                        client.BaseAddress = new Uri("https://myThingAPI/");
                        var message = new HttpRequestMessage(HttpMethod.Post, "/token");
    
                        // Add your login id and secret key here with the format you want to send
                        message.Content = new StringContent(string.Format("userName={0}&password={1}", UserName, Password));
                        var result = await client.SendAsync(message);
                        return result;
                    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-10-16
      • 1970-01-01
      • 2018-09-11
      • 2018-12-23
      • 1970-01-01
      • 2012-10-27
      • 1970-01-01
      相关资源
      最近更新 更多