上传文件时从 graphql 中获取臭名昭著的 400 错误,调试显示在 graphql-upload 中填充的数据

问题描述

我知道这是一个常见问题,而且我已确保应用发送正确的数据。我什至添加了日志记录以显示字段已正确填充。

我注意到的一件事是我在 parser.once('finish' () => {}) 中的 console.log 没有被调用,这就是“Missing multipart field”错误的来源.任何见解将不胜感激。

progressRequest - operations called {
  variables: { file: null,name: 'test' },  query: 'mutation ($file: Upload!,$name: String!) {\n' +
    '  createDocument(file: $file,name: $name) {\n' +
    '    id\n' +
    '    name\n' +
    '    __typename\n' +
    '  }\n' +
    '}\n'
}
processRequest - map called { '1': [ 'variables.file' ] }
processRequest - map entries [ [ '1',[ 'variables.file' ] ] ]
processRequest - map complete Map(1) {
  '1' => Upload {
    resolve: [Function (anonymous)],    reject: [Function (anonymous)],    promise: Promise { <pending> }
  }
}
processRequest - release Map(1) {
  '1' => Upload {
    resolve: [Function (anonymous)],    promise: Promise { [Object] },    file: {
      filename: 'file.docx',      mimetype: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',      encoding: '7bit',      createReadStream: [Function: createReadStream]
    }
  }
}
BadRequestError: Missing multipart field ‘operations’ (https://github.com/jaydenseric/graphql-multipart-request-spec).

客户帖子有以下内容:

------WebKitFormBoundaryVcAmZ4u9BOEmAIVW
Content-Disposition: form-data; name="operations"

{"variables":{"file":null,"name":"test"},"query":"mutation ($file: Upload!,$name: String!) {\n  createDocument(file: $file,name: $name) {\n    id\n    name\n    __typename\n  }\n}\n"}
------WebKitFormBoundaryVcAmZ4u9BOEmAIVW
Content-Disposition: form-data; name="map"

{"1":["variables.file"]}
------WebKitFormBoundaryVcAmZ4u9BOEmAIVW
Content-Disposition: form-data; name="1"; filename="file.docx"
Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document


------WebKitFormBoundaryVcAmZ4u9BOEmAIVW--  

服务器打字稿:

import { FileUpload,GraphQLUpload } from "graphql-upload";
import { Mutation,Arg,Resolver } from "type-graphql";
import { Document } from "../Document";

@Resolver(Document)
export class DocumentResolver {

    @Mutation(() => Document)
    async createDocument(@Arg("name") name: string,@Arg("file",() => GraphQLUpload) file: FileUpload): Promise<Document> {
        console.warn(name,file);        
        return null; // dont care about getting anything back as long as I see my console message
    };
}

客户端打字稿:

import { Component } from "@angular/core";
import { Apollo,gql } from "apollo-angular";

@Component({
  selector: 'test-page',  templateUrl: './test.html'
})
export class TestPageComponent {

  constructor(private apollo: Apollo) { }

  public onFileSelected(e: any): void {
    if (e.target.validity.valid) {
      this.serverResponse = {};
      this.serverResponseErr = {};

      let file = e.target.files[0];
      this.loadFileApollo(file);
    }
  }

  public loadFileApollo(file: File): void {
    const GRAPHQL_CREATE_TEMPLATE = `
    mutation($file: Upload!,$name: String!) {
      createDocument(file: $file,name: $name) {
        id,        name
      }
    }`;
    // 
    //var ti = { file: file };
    this.apollo.mutate<any>({
      mutation: gql(GRAPHQL_CREATE_TEMPLATE),      variables: { file: file,name: "test" },      context: {
        useMultipart: true
      }
    }).subscribe(x=> console.warn(x));
  }
}

HTML:

  <div>
    Click this button to select a file and immediately upload it to the server
    <input class="btn btn-primary" type="file" (change)="onFileSelected($event)"/>
  </div>

解决方法

所以问题出在 Apollo 内部的 graphql-upload 实现上。如果您正在自动生成架构,我建议您禁用它们的上传并直接实现 graphql-upload。它们落后了很多版本,并且在两个实现之间发送请求时出现问题。

ApolloServer({ uploads: false });

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...