You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Windows Device Portal REST API部署Hololens应用遇CSRF及413错误求助

解决Hololens Device Portal API部署应用的两大问题:CSRF Token无效 & 413请求过大

我来帮你搞定这俩困扰你的问题,这都是Windows Device Portal API的典型坑,咱们一步步来拆解解决:

一、搞定CSRF Token Invalid错误

Windows Device Portal的CSRF防护不是只靠Cookie就行的,它需要同时携带Cookie和请求头里的CSRF Token,你之前只加了Cookie肯定不行,正确流程是这样的:

  1. 先获取有效的CSRF Token
    发送一个GET请求到Hololens Device Portal的/api/csrf接口,这个接口会返回JSON格式的响应,里面包含csrfToken字段;同时响应头里会有Set-Cookie,把这个Cookie(尤其是XSRF-TOKEN)保存到Cookie容器里。
    用RestSharp的示例代码大概是这样:

    var client = new RestClient("http://your-hololens-ip");
    client.CookieContainer = new CookieContainer(); // 要复用这个容器!
    
    // 先获取CSRF Token
    var csrfRequest = new RestRequest("/api/csrf", Method.Get);
    csrfRequest.AddHeader("Authorization", "Basic " + Convert.ToBase64String(Encoding.ASCII.GetBytes("username:password"))); // 替换成你的Device Portal账号密码
    var csrfResponse = await client.ExecuteAsync(csrfRequest);
    var csrfToken = JsonConvert.DeserializeObject<CsrfResponse>(csrfResponse.Content).csrfToken; // 要定义对应的CsrfResponse类
    
    // 此时CookieContainer已经自动保存了返回的Cookie
    
  2. 部署请求时同时携带Token和Cookie
    发送POST请求部署应用时,除了带上之前的Cookie容器,还要在请求头里添加X-CSRF-Token字段,值就是刚才拿到的csrfToken。
    示例代码片段:

    var deployRequest = new RestRequest("/api/apps/package", Method.Post);
    deployRequest.AddHeader("Authorization", "Basic " + Convert.ToBase64String(Encoding.ASCII.GetBytes("username:password")));
    deployRequest.AddHeader("X-CSRF-Token", csrfToken); // 关键!
    deployRequest.AddFile("package", "path/to/your/app.msix"); // 添加要部署的文件
    var deployResponse = await client.ExecuteAsync(deployRequest);
    
  3. Postman里的操作步骤

    • 先发送GET请求到/api/csrf,复制返回的csrfToken值
    • 在POST部署请求的Headers里添加X-CSRF-Token,值为刚才复制的token
    • 确保请求的Cookie里包含XSRF-TOKEN(Postman会自动保存之前请求的Cookie,只要你是同一个会话)

二、解决413 Payload Too Large错误

Web版Device Portal能传大文件是因为它用了分块上传,直接POST整个大文件会触发Device Portal的大小限制,所以你得用分块上传的API:

  1. 初始化上传会话
    发送POST请求到/api/apps/package/upload,请求头带CSRF Token和Authorization,请求体里指定文件名和总大小,获取会话ID:

    var initRequest = new RestRequest("/api/apps/package/upload", Method.Post);
    initRequest.AddHeader("Authorization", "Basic " + Convert.ToBase64String(Encoding.ASCII.GetBytes("username:password")));
    initRequest.AddHeader("X-CSRF-Token", csrfToken);
    initRequest.AddParameter("fileName", "your-app.msix");
    initRequest.AddParameter("fileSize", new FileInfo("path/to/your/app.msix").Length);
    var initResponse = await client.ExecuteAsync(initRequest);
    var sessionId = JsonConvert.DeserializeObject<UploadInitResponse>(initResponse.Content).sessionId; // 定义对应的类
    
  2. 分块上传文件
    把大文件分成若干块(比如每块10MB),依次发送PUT请求到/api/apps/package/upload/{sessionId},每个请求要带Content-Range头,指定当前块的字节范围:

    var fileBytes = File.ReadAllBytes("path/to/your/app.msix");
    int chunkSize = 10 * 1024 * 1024; // 10MB每块
    int totalChunks = (int)Math.Ceiling((double)fileBytes.Length / chunkSize);
    
    for (int i = 0; i < totalChunks; i++)
    {
        int start = i * chunkSize;
        int end = Math.Min(start + chunkSize - 1, fileBytes.Length - 1);
        var chunk = fileBytes.Skip(start).Take(end - start + 1).ToArray();
    
        var chunkRequest = new RestRequest($"/api/apps/package/upload/{sessionId}", Method.Put);
        chunkRequest.AddHeader("Authorization", "Basic " + Convert.ToBase64String(Encoding.ASCII.GetBytes("username:password")));
        chunkRequest.AddHeader("X-CSRF-Token", csrfToken);
        chunkRequest.AddHeader("Content-Range", $"bytes {start}-{end}/{fileBytes.Length}");
        chunkRequest.AddParameter("application/octet-stream", chunk, ParameterType.RequestBody);
        await client.ExecuteAsync(chunkRequest);
    }
    
  3. 提交上传完成部署
    所有块上传完后,发送POST请求到/api/apps/package/upload/{sessionId}/commit:

    var commitRequest = new RestRequest($"/api/apps/package/upload/{sessionId}/commit", Method.Post);
    commitRequest.AddHeader("Authorization", "Basic " + Convert.ToBase64String(Encoding.ASCII.GetBytes("username:password")));
    commitRequest.AddHeader("X-CSRF-Token", csrfToken);
    var commitResponse = await client.ExecuteAsync(commitRequest);
    

额外注意点

  • 一定要确保所有请求复用同一个CookieContainer,这样会话才能保持有效
  • Device Portal的账号密码要正确,Authorization头不能少,否则也会出现403错误
  • 分块大小可以根据网络情况调整,不用拘泥于10MB,只要不超过单请求的大小限制就行

内容的提问来源于stack exchange,提问作者elpha01

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 18:32:42