通过 POST httprequest 传输文件到 hololens(错误 429)

Transfer file to hololens via POST httprequest (error 429)

我在桌面应用程序上工作,通过 httprequesthololens 眼镜通信(hololens 通过 USB 连接),特别是,我想要读取和写入文件。为此,我使用以下代码:

class BuildDeployPortal
{
    // Consts
    public static readonly string API_FileQuery = @"http://{0}/api/filesystem/apps/file";

    // Classes & Structs
    public struct ConnectInfo
    {
        public ConnectInfo(string ip, string user, string password)
        {
            IP = ip;
            User = user;
            Password = password;
        }

        public string IP;
        public string User;
        public string Password;
    }

    public async static void GetFile(ConnectInfo connectInfo, string knownfolderid, string filename, string packagefullname, string path)
    {
        try
        {
            // Query
            string query = string.Format(API_FileQuery, connectInfo.IP);
            query += "?knownfolderid=" + Uri.EscapeUriString(knownfolderid);
            query += "&filename=" + Uri.EscapeUriString(filename);
            query += "&packagefullname=" + Uri.EscapeUriString(packagefullname);
            query += "&path=" + Uri.EscapeUriString(path);

            // Create http request
            var httpRequest = new HttpClient();

            httpRequest.DefaultRequestHeaders.Clear();
            httpRequest.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic",
                                                                                        EncodeTo64(connectInfo.User + ":" + connectInfo.Password));

            HttpResponseMessage resp = await httpRequest.GetAsync(query);

            byte[] responseMessage = await resp.Content.ReadAsByteArrayAsync();

        }
        catch (Exception ex)
        {
            //log some problems
        }

    }



    public async static void UploadFile(ConnectInfo connectInfo, string knownfolderid, string packagefullname, string path, string filePath)
    {
        try
        {
            // Query
            string query = string.Format(API_FileQuery, connectInfo.IP);
            query += "?knownfolderid=" + Uri.EscapeUriString(knownfolderid);
            query += "&packagefullname=" + Uri.EscapeUriString(packagefullname);
            query += "&path=" + Uri.EscapeUriString(path);

            //  Create http request
            var httpRequest = new HttpClient();

            httpRequest.DefaultRequestHeaders.Clear();
            httpRequest.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic",
                                                                                        EncodeTo64(connectInfo.User + ":" + connectInfo.Password));
            byte[] data = File.ReadAllBytes(filePath);
            ByteArrayContent byteContent = new ByteArrayContent(data);

            HttpResponseMessage resp = await httpRequest.PostAsync(query, byteContent);

            var responseMessage = await resp.Content.ReadAsStringAsync();

        }
        catch (Exception ex)
        {
            //log some problems
        }

    }


    // Helpers
    private static string EncodeTo64(string toEncode)
    {
        byte[] toEncodeAsBytes = Encoding.ASCII.GetBytes(toEncode);
        string returnValue = Convert.ToBase64String(toEncodeAsBytes);
        return returnValue;
    }
}

我给运行打电话

BuildDeployPortal.ConnectInfo co = new BuildDeployPortal.ConnectInfo("127.0.0.1:10080", "user", "pass");

//get file
BuildDeployPortal.GetFile(co, "LocalAppData", "2017-01-25-09-04-21_TestFile.csv", "app_full_package_name", "\LocalState");

//upload file
BuildDeployPortal.UploadFile(co, "LocalAppData", "app_full_package_name", "\LocalState",
            "C:\Users\myuser\Desktop\info.json");

GetFile 方法工作正常并为我提供了我想要的文件,但 UploadFile 方法为我提供了以下响应:StatusCode:429,ReasonPhrase:'Too Many Requests'。如果我在执行期间只 运行 其中一个,结果相同。

我真的不明白为什么会出现这个错误,我只发送了 1 个请求(或者我遗漏了什么)。

有关信息,可以找到 REST API 定义 there

谢谢

我并没有真正回答我的问题(为什么会出现此错误 429),但我提供了上传文件的替代解决方案。

我下载了 this solution 以获取 WindowsDevicePortalWrapper 库。 然后我调用以下代码上传文件:

IDevicePortalConnection connection = new DefaultDevicePortalConnection("http://127.0.0.1:10080", "user", "password");
DevicePortal dp = new DevicePortal(connection);
//write file
await dp.UploadFileAsync("LocalAppData", "C:\Users\ng1dd32\Desktop\info.json", "\LocalState", "Lexington_1.0.0.0_x86__ph1m9x8skttmg");

调试问题

问题是Chrome62发送了空的content-typeheader,而Chrome61did发送了content-type header 正确为 multipart/form-data.

的原因是微软自己的FileExplorer.js代码用contentType: ""调用了jQuery.ajax(...),所以留给浏览器解释一个空字符串。

摘自FileExplorer.js

$.ajax({url:"/api/filesystem/apps/file?"+$.param(r),cache:!1,contentType:"",processData:!1,data:n,type:"post"}).done(...)

REST API definition you linked from Microsoft 未能指定任何请求 Headers,也未能指定请求 Body,因此没有规范可用来确定正确的 [= =61=] 和 Body.

FWIW,微软自己的 C# Device Portal REST API wrapper 总是发送 content-type header:

string contentType = string.Format("multipart/form-data; boundary={0}", boundaryString);

解决方案

我创建了一个小书签,可以在设备门户的 FileExplorer 页面上正确上传文件。

扩展版

(function(jQuery) {
var pathLinkData = jQuery(".pathLink:last-child").data(),
    path = pathLinkData.path,
    packagename = pathLinkData.packagename,
    knownfolderid = pathLinkData.knownfolderid,
    url = '/api/filesystem/apps/file?knownfolderid=' + knownfolderid + '&packagefullname=' + packagename + '&path=%5C%5C' + path,
    file_data = jQuery('#fileToUpload')[0].files[0],
    form_data = new FormData();

  form_data.append('file', file_data, file_data.name);

  jQuery.ajax({
    url: url,
    dataType: 'text',
    cache: false,
    contentType: false,
    processData: false,
    data: form_data,
    type: 'POST',
    error: function(xhr, textStatus, error) { console.error(error) },
    success: function(res){
      alert('uploaded');
      console.log(res);
    }
  });
})(jQuery);

紧凑型可复制小书签版本(也适用于 inspector/debugger 控制台)

javascript:(function(jQuery){var pathLinkData=jQuery('.pathLink:last-child').data(),path=pathLinkData.path,packagename=pathLinkData.packagename,knownfolderid=pathLinkData.knownfolderid,url='/api/filesystem/apps/file?knownfolderid='+knownfolderid+'&packagefullname='+packagename+'&path=%5C%5C'+path,file_data=jQuery('#fileToUpload')[0].files[0],form_data=new FormData();form_data.append('file',file_data,file_data.name);jQuery.ajax({url:url,dataType:'text',cache:false,contentType:false,processData:false,data:form_data,type:'POST',error:function(xhr,textStatus,error){console.error(error)},success:function(res){alert("uploaded");console.log(res);}});})(jQuery);

(我已经为 Hololens 开发了一年多,并在我的每台计算机分别升级到 Chrome 62 时发现了这一点。)