1

当我通过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

4

2 回答 2

1

你好杰克逊,你应该改变 esp 软件。你不使用https://github.com/esp8266/Arduino/tree/master/libraries/ESP8266HTTPUpdateServer/examples因为我们上传了服务器端。你可以使用https://github.com/esp8266/Arduino/blob/master/libraries/ESP8266WebServer/examples/WebUpdate/WebUpdate.ino这个例子,你会改变这部分

 server.on("/update", HTTP_POST, [](){
  server.sendHeader("Connection", "close");
  server.sendHeader("Access-Control-Allow-Methods", "GET, POST, PUT");
  server.sendHeader("Access-Control-Allow-Headers","Origin, X-Requested-With, Content-Type, Accept, Authorization");
  server.send(200, "text/plain", (Update.hasError())?"FAIL":"OK");
  ESP.restart();
}

我希望能解决你的问题 :) 享受编码

于 2017-02-20T05:18:24.590 回答
0

尝试使用“图像”名称

formData.Add(postContent, "image", "firmware.bin");
于 2017-02-20T05:25:26.920 回答