无法在 GKE 上部署 Google 个云端点

Unable to deploy Google cloud endpoints on GKE

遵循 GCE 教程 https://cloud.google.com/endpoints/docs/openapi/get-started-kubernetes-engine 后,我决定为我的 Spring 启动应用程序部署云端点。

我使用 swagger-ui 生成了我的 openapi 文件。我在创建云端点的过程中遇到了这些错误,我真的不知道为什么:

> gcloud endpoints services deploy openapi.yaml ERROR:
> (gcloud.endpoints.services.deploy) INVALID_ARGUMENT: Cannot convert to
> service config. 'location: "unknown location" kind: ERROR message:
> "http: In path template \'/api/apk/\': unexpected end of input \'/\'."
> 
>  location: "unknown location" kind: ERROR message: "http: In path
> template \'/api/apk/\': unexpected end of input \'/\'."
> 
>  location: "unknown location" kind: ERROR message: "http: In path
> template \'/api/apk/category/\': unexpected end of input \'/\'."
> 
>  location: "unknown location" kind: ERROR message: "http: In path
> template \'/api/apk/category/\': unexpected end of input \'/\'."
> 
>  location: "unknown location" kind: ERROR message: "http: repeated
> message field \'google.protobuf.Struct.fields\' referred to by message
> \'AddApkFileUsingPOSTRequest\                                         
> ' cannot be mapped as an HTTP parameter."
> 
>  location: "unknown location" kind: ERROR message: "http: cyclic
> message field \'google.protobuf.Struct.FieldsEntry.value\' referred to
> by message \'AddApkFileUsingPOS                                       
> TRequest\' in method \'method
> 1.mapk_api_gara_store.AddApkFileUsingPOST\' cannot be mapped as an HTTP parameter."
> 
>  location: "unknown location" kind: ERROR message: "http: cyclic
> message field \'google.protobuf.ListValue.values\' referred to by
> message \'AddApkFileUsingPOSTRequest                                  
> \' in method \'method 1.mapk_api_gara_store.AddApkFileUsingPOST\'
> cannot be mapped as an HTTP parameter."
> 
>  location: "unknown location" kind: ERROR message: "http: repeated
> message field \'google.protobuf.Struct.fields\' referred to by message
> \'UploadOrUpdateCoverImageUsi                                         
> ngPOSTRequest\' cannot be mapped as an HTTP parameter."
> 
>  location: "unknown location" kind: ERROR message: "http: cyclic
> message field \'google.protobuf.Struct.FieldsEntry.value\' referred to
> by message \'UploadOrUpdateCove                                       
> rImageUsingPOSTRequest\' in method \'method
> 1.mapk_api_gara_store.UploadOrUpdateCoverImageUsingPOST\' cannot be mapped as an                                                          
> HTTP parameter."
> 
>  location: "unknown location" kind: ERROR message: "http: cyclic
> message field \'google.protobuf.ListValue.values\' referred to by
> message \'UploadOrUpdateCoverImageUs                                  
> ingPOSTRequest\' in method \'method
> 1.mapk_api_gara_store.UploadOrUpdateCoverImageUsingPOST\' cannot be mapped as an HTTP par                                                 
> ameter."
> 
>  location: "unknown location" kind: ERROR message: "http: repeated
> message field \'google.protobuf.Struct.fields\' referred to by message
> \'UploadOrUpdateIconImageUsin                                         
> gPOSTRequest\' cannot be mapped as an HTTP parameter."
> 
>  location: "unknown location" kind: ERROR message: "http: cyclic
> message field \'google.protobuf.Struct.FieldsEntry.value\' referred to
> by message \'UploadOrUpdateIcon                                       
> ImageUsingPOSTRequest\' in method \'method
> 1.mapk_api_gara_store.UploadOrUpdateIconImageUsingPOST\' cannot be mapped as an HT                                                       
> TP parameter."
> 
>  location: "unknown location" kind: ERROR message: "http: cyclic
> message field \'google.protobuf.ListValue.values\' referred to by
> message \'UploadOrUpdateIconImageUsi                                  
> ngPOSTRequest\' in method \'method
> 1.mapk_api_gara_store.UploadOrUpdateIconImageUsingPOST\' cannot be mapped as an HTTP param                                               
> eter."
> 
>  location: "unknown location" kind: ERROR message: "http: repeated
> message field \'google.protobuf.Struct.fields\' referred to by message
> \'AddOrUpdateScreenShotUsingP                                         
> OSTRequest\' cannot be mapped as an HTTP parameter."
> 
>  location: "unknown location" kind: ERROR message: "http: cyclic
> message field \'google.protobuf.Struct.FieldsEntry.value\' referred to
> by message \'AddOrUpdateScreenS                                       
> hotUsingPOSTRequest\' in method \'method
> 1.mapk_api_gara_store.AddOrUpdateScreenShotUsingPOST\' cannot be mapped as an HTTP p                                                   
> arameter."
> 
>  location: "unknown location" kind: ERROR message: "http: cyclic
> message field \'google.protobuf.ListValue.values\' referred to by
> message \'AddOrUpdateScreenShotUsing                                  
> POSTRequest\' in method \'method
> 1.mapk_api_gara_store.AddOrUpdateScreenShotUsingPOST\' cannot be mapped as an HTTP parameter                                           
> ."

我的 openApi 文件如下:

swagger: '2.0'
info:
    description: 'Api Documentation'
    version: '1.0.0'
    title: 'Api Documentation for apk micro service'
    termsOfService: 'urn:tos'
    contact: {}
    license:
        name: 'Apache 2.0'
        url: 'http://www.apache.org/licenses/LICENSE-2.0'
host: "mapk.api.gara.store"
basePath: /
tags:
    -
        name: apk-service-controller
        description: 'Apk Service Controller'
    -
        name: category-controller
        description: 'Category Controller'

schemes:
# Uncomment the next line if you configure SSL for this API.
# - "https"
  - "http"
paths:
    /api/apk/:
        post:
            tags: [apk-service-controller]
            summary: create
            operationId: createUsingPOST
            consumes: [application/json]
            produces: [application/json]
            parameters: [{in: body, name: apkDto, description: apkDto, required: true, schema: {$ref: '#/definitions/ApkDto'}}]
            security:
              - api_key: []
            responses: {'200': {description: OK, schema: {$ref: '#/definitions/Apk'}}, '201': {description: Created}, '401': {description: Unauthorized}, '403': {description: Forbidden}, '404': {description: 'Not Found'}}
        put:
            tags: [apk-service-controller]
            summary: update
            operationId: updateUsingPUT
            consumes: [application/json]
            produces: [application/json]
            parameters: [{in: body, name: apkDto, description: apkDto, required: true, schema: {$ref: '#/definitions/ApkDto'}}]
            security:
              - api_key: []
            responses: {'200': {description: OK, schema: {$ref: '#/definitions/Apk'}}, '201': {description: Created}, '401': {description: Unauthorized}, '403': {description: Forbidden}, '404': {description: 'Not Found'}}
    /api/apk/activateapkversion:
        post:
            tags: [apk-service-controller]
            summary: activateApkVersion
            operationId: activateApkVersionUsingPOST
            consumes: [application/json]
            produces: ['*/*']
            parameters: [{name: apkId, in: query, description: apkId, required: true, type: integer, format: int64}, {name: codeVersion, in: query, description: codeVersion, required: true, type: integer, format: int64}]
            security:
              - api_key: []
            responses: {'200': {description: OK, schema: {$ref: '#/definitions/Apk'}}, '201': {description: Created}, '401': {description: Unauthorized}, '403': {description: Forbidden}, '404': {description: 'Not Found'}}
    /api/apk/addapk:
        post:
            tags: [apk-service-controller]
            summary: addApkFile
            operationId: addApkFileUsingPOST
            consumes: [multipart/form-data]
            produces: ['*/*']
            parameters: [{name: file, in: formData, description: file, required: true, type: file}, {name: apkId, in: query, description: apkId, required: true, type: integer, format: int64}]
            security:
              - api_key: []
            responses: {'200': {description: OK, schema: {$ref: '#/definitions/ApkVersion'}}, '201': {description: Created}, '401': {description: Unauthorized}, '403': {description: Forbidden}, '404': {description: 'Not Found'}}
    /api/apk/addorupdatecover:
        post:
            tags: [apk-service-controller]
            summary: uploadOrUpdateCoverImage
            operationId: uploadOrUpdateCoverImageUsingPOST
            consumes: [multipart/form-data]
            produces: ['*/*']
            parameters: [{name: file, in: formData, description: file, required: true, type: file}, {name: apkId, in: query, description: apkId, required: true, type: integer, format: int64}]
            security:
              - api_key: []
            responses: {'200': {description: OK, schema: {$ref: '#/definitions/Apk'}}, '201': {description: Created}, '401': {description: Unauthorized}, '403': {description: Forbidden}, '404': {description: 'Not Found'}}
    /api/apk/addorupdateicon:
        post:
            tags: [apk-service-controller]
            summary: uploadOrUpdateIconImage
            operationId: uploadOrUpdateIconImageUsingPOST
            consumes: [multipart/form-data]
            produces: ['*/*']
            parameters: [{name: file, in: formData, description: file, required: true, type: file}, {name: apkId, in: query, description: apkId, required: true, type: integer, format: int64}]
            security:
              - api_key: []
            responses: {'200': {description: OK, schema: {$ref: '#/definitions/Apk'}}, '201': {description: Created}, '401': {description: Unauthorized}, '403': {description: Forbidden}, '404': {description: 'Not Found'}}
    /api/apk/addscreenshots:
        post:
            tags: [apk-service-controller]
            summary: addOrUpdateScreenShot
            operationId: addOrUpdateScreenShotUsingPOST
            consumes: [multipart/form-data]
            produces: ['*/*']
            parameters: [{name: file, in: formData, description: file, required: true, type: file}, {name: apkId, in: query, description: apkId, required: true, type: integer, format: int64}, {name: index, in: query, description: index, required: true, type: integer, format: int32}]
            security:
              - api_key: []
            responses: {'200': {description: OK, schema: {$ref: '#/definitions/Apk'}}, '201': {description: Created}, '401': {description: Unauthorized}, '403': {description: Forbidden}, '404': {description: 'Not Found'}}
    /api/apk/category/:
        get:
            tags: [category-controller]
            summary: getAllCategories
            operationId: getAllCategoriesUsingGET
            produces: [application/json]
            responses: {'200': {description: OK, schema: {type: array, items: {$ref: '#/definitions/Category'}}}, '401': {description: Unauthorized}, '403': {description: Forbidden}, '404': {description: 'Not Found'}}
            security:
              - api_key: []
        post:
            tags: [category-controller]
            summary: createCategory
            operationId: createCategoryUsingPOST
            consumes: [application/json]
            produces: [application/json]
            parameters: [{name: categoryname, in: query, description: categoryname, required: true, type: string}]
            security:
              - api_key: []
            responses: {'200': {description: OK, schema: {$ref: '#/definitions/Category'}}, '201': {description: Created}, '401': {description: Unauthorized}, '403': {description: Forbidden}, '404': {description: 'Not Found'}}
    /api/apk/category/addsubcategory:
        post:
            tags: [category-controller]
            summary: addSubCategory
            operationId: addSubCategoryUsingPOST
            consumes: [application/json]
            produces: ['*/*']
            parameters: [{name: categoryId, in: query, description: categoryId, required: true, type: integer, format: int64}, {name: subcategory, in: query, description: subcategory, required: true, type: string}]
            security:
              - api_key: []
            responses: {'200': {description: OK, schema: {$ref: '#/definitions/Category'}}, '201': {description: Created}, '401': {description: Unauthorized}, '403': {description: Forbidden}, '404': {description: 'Not Found'}}
    /api/apk/category/removesubcategory:
        post:
            tags: [category-controller]
            summary: removeSubCategory
            operationId: removeSubCategoryUsingPOST
            consumes: [application/json]
            produces: ['*/*']
            parameters: [{name: categoryId, in: query, description: categoryId, required: true, type: integer, format: int64}, {name: subCategoryId, in: query, description: subCategoryId, required: true, type: integer, format: int64}]
            security:
              - api_key: []
            responses: {'200': {description: OK, schema: {$ref: '#/definitions/Category'}}, '201': {description: Created}, '401': {description: Unauthorized}, '403': {description: Forbidden}, '404': {description: 'Not Found'}}
    '/api/apk/category/{categoryId}':
        delete:
            tags: [category-controller]
            summary: delete
            operationId: deleteUsingDELETE_1
            produces: ['*/*']
            parameters: [{name: categoryId, in: path, description: categoryId, required: true, type: integer, format: int64}]
            responses: {'200': {description: OK}, '204': {description: 'No Content'}, '401': {description: Unauthorized}, '403': {description: Forbidden}}
            security:
              - api_key: []
    '/api/apk/category/{id}':
        get:
            tags: [category-controller]
            summary: getCategoyById
            operationId: getCategoyByIdUsingGET
            produces: ['*/*']
            parameters: [{name: id, in: path, description: id, required: true, type: integer, format: int64}]
            responses: {'200': {description: OK, schema: {$ref: '#/definitions/Category'}}, '401': {description: Unauthorized}, '403': {description: Forbidden}, '404': {description: 'Not Found'}}
            security:
              - api_key: []
    '/api/apk/company/{companyId}':
        get:
            tags: [apk-service-controller]
            summary: getAllWebtoonByCompany
            operationId: getAllWebtoonByCompanyUsingGET
            produces: ['*/*']
            parameters: [{name: companyId, in: query, description: companyId, required: false, type: integer, format: int64}]
            responses: {'200': {description: OK, schema: {type: array, items: {$ref: '#/definitions/Apk'}}}, '401': {description: Unauthorized}, '403': {description: Forbidden}, '404': {description: 'Not Found'}}
            security:
              - api_key: []
    /api/apk/reviewandrated:
        post:
            tags: [apk-service-controller]
            summary: addAndUpdateReviewAndNote
            operationId: addAndUpdateReviewAndNoteUsingPOST
            consumes: [application/json]
            produces: [application/json]
            parameters: [{in: body, name: apkReviewDto, description: apkReviewDto, required: true, schema: {$ref: '#/definitions/ApkReviewDto'}}]
            security:
              - api_key: []
            responses: {'200': {description: OK, schema: {$ref: '#/definitions/Apk'}}, '201': {description: Created}, '401': {description: Unauthorized}, '403': {description: Forbidden}, '404': {description: 'Not Found'}}
    '/api/apk/{id}':
        get:
            tags: [apk-service-controller]
            summary: getApkById
            operationId: getApkByIdUsingGET
            produces: ['*/*']
            parameters: [{name: id, in: path, description: id, required: true, type: integer, format: int64}]
            security:
              - api_key: []            
            responses: {'200': {description: OK, schema: {$ref: '#/definitions/Apk'}}, '401': {description: Unauthorized}, '403': {description: Forbidden}, '404': {description: 'Not Found'}}
        delete:
            tags: [apk-service-controller]
            summary: delete
            operationId: deleteUsingDELETE
            produces: ['*/*']
            parameters: [{name: id, in: path, description: id, required: true, type: integer, format: int64}]
            security:
              - api_key: []
            responses: {'200': {description: OK}, '204': {description: 'No Content'}, '401': {description: Unauthorized}, '403': {description: Forbidden}}

我的文件有什么问题?

编辑:删除路径前面的“/”后,所有关于意外结束的错误都消失了。但我仍然有 google 个错误:

 `ERROR: (gcloud.endpoints.services.deploy) INVALID_ARGUMENT: Cannot convert to service config. 'location: "unknown location" kind: ERROR message: "http: repeated message field \'google.protobuf.Struct.fields\' referred to by message \'AddApkFileUsingPOSTRequest\' cannot be mapped as an HTTP parameter."

 location: "unknown location" kind: ERROR message: "http: cyclic message field \'google.protobuf.Struct.FieldsEntry.value\' referred to by message \'AddApkFileUsingPOSTRequest\' in method \'method
1.mapk_api_gara_store.AddApkFileUsingPOST\' cannot be mapped as an HTTP parameter."

 location: "unknown location" kind: ERROR message: "http: cyclic message field \'google.protobuf.ListValue.values\' referred to by message \'AddApkFileUsingPOSTRequest\' in method \'method
1.mapk_api_gara_store.AddApkFileUsingPOST\' cannot be mapped as an HTTP parameter."

 location: "unknown location" kind: ERROR message: "http: repeated message field \'google.protobuf.Struct.fields\' referred to by message \'UploadOrUpdateCoverImageUsingPOSTRequest\' cannot be mapped as an HTTP parameter."

 location: "unknown location" kind: ERROR message: "http: cyclic message field \'google.protobuf.Struct.FieldsEntry.value\' referred to by message \'UploadOrUpdateCoverImageUsingPOSTRequest\' in method \'method 1.mapk_api_gara_store.UploadOrUpdateCoverImageUsingPOST\' cannot be mapped as an HTTP parameter."

 location: "unknown location" kind: ERROR message: "http: cyclic message field \'google.protobuf.ListValue.values\' referred to by message \'UploadOrUpdateCoverImageUsingPOSTRequest\' in method \'method 1.mapk_api_gara_store.UploadOrUpdateCoverImageUsingPOST\' cannot be mapped as an HTTP parameter."

 location: "unknown location" kind: ERROR message: "http: repeated message field \'google.protobuf.Struct.fields\' referred to by message \'UploadOrUpdateIconImageUsingPOSTRequest\' cannot be mapped as an HTTP parameter."

 location: "unknown location" kind: ERROR message: "http: cyclic message field \'google.protobuf.Struct.FieldsEntry.value\' referred to by message \'UploadOrUpdateIconImageUsingPOSTRequest\' in method \'method 1.mapk_api_gara_store.UploadOrUpdateIconImageUsingPOST\' cannot be mapped as an HTTP parameter."

 location: "unknown location" kind: ERROR message: "http: cyclic message field \'google.protobuf.ListValue.values\' referred to by message \'UploadOrUpdateIconImageUsingPOSTRequest\' in method \'method
1.mapk_api_gara_store.UploadOrUpdateIconImageUsingPOST\' cannot be mapped as an HTTP parameter."

 location: "unknown location" kind: ERROR message: "http: repeated message field \'google.protobuf.Struct.fields\' referred to by message \'AddOrUpdateScreenShotUsingPOSTRequest\' cannot be mapped as an HTTP parameter."

 location: "unknown location" kind: ERROR message: "http: cyclic message field \'google.protobuf.Struct.FieldsEntry.value\' referred to by message \'AddOrUpdateScreenShotUsingPOSTRequest\' in method \'method 1.mapk_api_gara_store.AddOrUpdateScreenShotUsingPOST\' cannot be mapped as an HTTP parameter."

 location: "unknown location" kind: ERROR message: "http: cyclic message field \'google.protobuf.ListValue.values\' referred to by message \'AddOrUpdateScreenShotUsingPOSTRequest\' in method \'method
1.mapk_api_gara_store.AddOrUpdateScreenShotUsingPOST\' cannot be mapped as an HTTP parameter."

正确答案由艾威尔创立 " I changed it to type: "string", format "binary" and it fixed everything (swagger 2.0)"