当我通过HttpClient
. 我用它上传固件到 ESP8266 Arduino 的 OTA 固件升级接口(参见示例:https ://github.com/esp8266/Arduino/tree/master/libraries/ESP8266HTTPUpdateServer/examples ),但它抛出异常说
“WinHttpException:服务器返回无效或无法识别的响应”
当我通过 cURL 上传固件图像时,它可以使用以下命令完全正常:
curl -F "image=@firmware.bin" 192.168.1.104/update
我试过用 Fiddler 调试,它告诉我我有504 网关超时。 但如果我使用 cURL,它就不会发生。
我猜这可能是由 ESP8266 固件 OTA 更新 API 内部的一些错误引起的,而我的程序没有生成可以“满足”API 的标头,因此以某种方式被拒绝。如果可能的话,我想问一下这个问题有什么解决方法吗?提前致谢!
这是 Fiddler 捕获的 cURL 的原始结果:
POST http://192.168.1.104/update HTTP/1.1
Host: 192.168.1.104
User-Agent: curl/7.51.0
Accept: */*
Connection: Keep-Alive
Content-Length: 335869
Expect: 100-continue
Content-Type: multipart/form-data; boundary=------------------------32e3208a349a700d
--------------------------32e3208a349a700d
Content-Disposition: form-data; name="image"; filename="firmware.bin"
Content-Type: application/octet-stream
.......(Firmware File Content).......
这是我的程序的原始结果:
POST http://192.168.1.104/update HTTP/1.1
Connection: Keep-Alive
Content-Type: multipart/form-data; boundary="----TwilightFirmware"
Accept-Encoding: gzip, deflate
Content-Length: 335857
Host: 192.168.1.104
------TwilightFirmware
Content-Type: application/octet-stream
Content-Disposition: form-data; name=update; filename=firmware.bin; filename*=utf-8''firmware.bin
.............(Firmware file Content)...........
这是我的(部分)C#代码,
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Net.Http;
using System.Diagnostics;
namespace JasmineApp.Core
{
class LocalFirmwareUpdater
{
public async Task<bool> UploadLocalFirmware(string baseUrl, string filePath)
{
Debug.WriteLine("[Core.FirmwareUpdater] Base URL is: " + baseUrl);
HttpCommandHandler httpHandler = new HttpCommandHandler();
httpHandler.SetHttpBaseUrl(baseUrl);
byte[] firmwareContent = File.ReadAllBytes(filePath);
// HttpContent postContent = new StreamContent(firmwareStream);
HttpContent postContent = new ByteArrayContent(firmwareContent);
postContent.Headers.Add("Content-Type", "application/octet-stream");
var formData = new MultipartFormDataContent("----TwilightFirmware");
formData.Add(postContent, "update", "firmware.bin");
string result = await httpHandler.ExecutePostAsync("/update", formData);
// string result = await httpHandler.ExecutePostAsync("/update", postContent);
return (
result.Equals(string.Empty)
|| result == null
|| result.Contains("Fail")) ? false : true;
}
}
}
...和 HTTP 处理程序代码在这里:
public async Task<string> ExecutePostAsync(string pathAndQuery, MultipartFormDataContent content)
{
Debug.WriteLine("[Core.HttpHandler] Request POST URL: " + BaseUrl + pathAndQuery);
using(var client = this.getHttpClient())
{
client.Timeout = TimeSpan.FromSeconds(2000000);
var httpResponseMessage = client.PostAsync(pathAndQuery, content).Result;
if(httpResponseMessage != null)
{
string responseResult = await httpResponseMessage.Content.ReadAsStringAsync();
Debug.WriteLine("[Core.HttpCommandHandler] POST return message: " + httpResponseMessage.Content.ReadAsStringAsync().Result);
return responseResult;
}
else
{
// Return an empty string to avoid exceptions
// Don't need to worrry if it's empty.
return string.Empty;
}
}
顺便说一句,如果有必要,你可以在 GitHub 上查看我的完整代码。这是链接:https ://github.com/huming2207/JasmineApp.Windows