【问题标题】:can use API GET but not API POST可以使用 API GET 但不能使用 API POST
【发布时间】:2018-09-14 20:32:53
【问题描述】:

我正在 VS 2013 中处理现有的 Windows 服务项目。

我添加了一个 Web API 控制器类,我现在不记得它是 (v2.1) 还是 (v1) 控制器类...。无论如何,我将其称为 SyncPersonnelViaAwsApiController

我试图从 AWS lambda 调用它...所以如果我调用 GET

public string Get(int id)
    {
        return "value";
    }

with const req = https.request('https://actualUrlAddress/api/SyncPersonnelViaAwsApi/Get/4', (res) => {

我得到returned body: undefined"value" 这是正确的。 但是,如果我尝试打电话

const req = https.request('https://actualUrlAddress/api/SyncPersonnelViaAwsApi/SapCall', (res) => {

我收到returned body: undefined{"Message":"The requested resource does not support http method 'GET'."}

 //// POST api/<controller>
    public string SapCall([FromBody]string xmlFile)
    {
        string responseMsg = "Failed Import User";

        if (!IsNewestVersionOfXMLFile(xmlFile))
        {
            responseMsg = "Not latest version of file, update not performed";
        }
        else
        {
            Business.PersonnelReplicate personnelReplicate = BusinessLogic.SynchronisePersonnel.BuildFromDataContractXml<Business.PersonnelReplicate>(xmlFile);
            bool result = Service.Personnel.SynchroniseCache(personnelReplicate);

            if (result)
            {
                responseMsg = "Success Import Sap Cache User";
            }
        }

        return "{\"response\" : \" " + responseMsg + " \" , \"isNewActiveDirectoryUser\" : \" false \"}";
    }

有谁知道为什么它适用于 GET 而不是 POST?

因为我们可以点击让我确信它不是 lambda,但我已经将它包含在内以防万一

const AWS = require('aws-sdk');
const https = require('https');
var s3 = new AWS.S3();
var un;
var pw;
var seralizedXmlFile;


let index = function index(event, context, callback) {

    // For the purpose of testing I have populated the bucket and key params with objects that already exist in the S3 bucket  
    var params = {
    Bucket: "testbucketthur7thdec",
    Key: "personnelData_50312474_636403151354943757.xml"
};


// Get Object from S3 bucket and add to 'seralizedXmlFile'
s3.getObject(params, function (data, err) {
    console.log("get object from S3 bucket");
    if (err) {
        // an error occurred
    }
    else
    {
        console.log("data " + data);
        // populate seralizedXmlFile with data from S3 bucket
        let seralizedXmlFile = err.Body.toString('utf-8'); // Use the encoding necessary
        console.log("objectData " + seralizedXmlFile);
    }

});

    // set params
    var ssm = new AWS.SSM({ region: 'Usa2' });
    console.log('Instatiated SSM');
    var paramsx = {
        'Names': ['/Sap/ServiceUsername', '/Sap/ServicePassword'],
        'WithDecryption': true
    };

// password and username
    ssm.getParameters(paramsx, function (err, data) {
        console.log('Getting parameter');
        if (err) console.log(err, err.stack); // an error occurred
        else {
            console.log('data: ' + JSON.stringify(data));           // successful response
            console.log('password: ' + data.Parameters[0].Value);
            console.log('username: ' + data.Parameters[1].Value);
            pw = data.Parameters[0].Value;
            un = data.Parameters[1].Value;
        }


        // request to external api application & remove dependency on ssl
        process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";

        //POST DOES NOT WORK
        const req = https.request('https://actualUrlAddress/api/SyncPersonnelViaAwsApi/SapEaiCall', (res) => {
        //GET WORKS
       // const req = https.request('https://actualUrlAddress/api/SyncPersonnelViaAwsApi/Get/4', (res) => {

            res.headers + 'Authorization: Basic ' + un + ':' + pw;
            let body = seralizedXmlFile;
            console.log('seralizedXmlFile: ' + seralizedXmlFile); 
            console.log('Status:', res.statusCode);
            console.log('Headers:', JSON.stringify(res.headers));

            res.setEncoding('utf8');
            res.on('data', (chunk) => body += chunk);
            res.on('end', () => {
                console.log('Successfully processed HTTPS response');
                callback(null, body);
                console.log('returned body:', body);

            });
        });
        req.end();
    });
};
exports.handler = index;

更新 感谢@Thangadurai 发帖AWS Lambda - NodeJS POST request and asynch write/read file

我能够包含一个 post_options...请查看更新的 lambda

          // An object of options to indicate where to post to
    var post_options = {
        host: 'https://actualUrlAddress',
        port: '80',
        path: '/api/SyncPersonnelViaAwsApi/SapEaiCall',
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            'Content-Length': post_data.length
        }
    };

 const req = https.request(post_options, (res) => {
   res.headers + 'Authorization: Basic ' + un + ':' + pw;
            let body = seralizedXmlFile;
            console.log('seralizedXmlFile: ' + seralizedXmlFile); 
            console.log('Status:', res.statusCode);
            console.log('Headers:', JSON.stringify(res.headers));

            res.setEncoding('utf8');
            res.on('data', (chunk) => body += chunk);
            res.on('end', () => {
                console.log('Successfully processed HTTPS response');
                callback(null, body);
                console.log('returned body:', body);

            });
        });
        req.end();

现在标记为错误:

Error: getaddrinfo ENOTFOUND http://actualUrlAddress http://actualUrlAddress.private:80

我之前遇到过这个 getaggrinfo ENOTFOUND 错误,这意味着它找不到地址....但是主机名和 api 路径是否正确?

我正在尝试联系

const req = https.request('https://actualUrlAddress/api/SyncPersonnelViaAwsApi/SapCall

是的,端口是 80

任何帮助将不胜感激 塔 M

【问题讨论】:

  • 错误提示/GET不受支持,而不是/POST不受支持。
  • 从您的描述和代码来看,GET 有效,因为 API 方法 https://actualUrlAddress/api/SyncPersonnelViaAwsApi/Get/4 旨在接受 HTTP GET 请求。但是另一个 API 方法 SapCall 仅支持 HTTP POST 动词,我假设这是因为 API 方法定义中的注释是这样说的,并且 [FromBody] 属性也表明了这一点。 [注意:HTTP GET 请求不会有正文。
  • @AluanHaddad 感谢您的回复,我知道错误的含义,但这是我尝试调用 POST 时看到的错误
  • @Thangadurai 谢谢回复,请问body是空的是什么意思?
  • @John 我认为你没有发送帖子请求。

标签: c# node.js post get aws-lambda


【解决方案1】:

直接跳到更新部分(据我所知,其他一切都不相关)。选项应如下所示:

var post_options = {
    host: 'actualUrlAddress',
    protocol: 'https:'
    port: '443',
    path: '/api/SyncPersonnelViaAwsApi/SapEaiCall',
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
        'Content-Length': post_data.length
    }
};

由于documentation表示,主机和协议是两个独立的属性,SSL端口不太可能是80,通常是443。

【讨论】:

【解决方案2】:

鉴于正在使用 Web API,假设默认路由也已配置。

我建议启用属性路由

参考Attribute Routing in ASP.NET Web API 2

public static class WebApiConfig {
    public static void Register(HttpConfiguration config) {
        // Attribute routing.
        config.MapHttpAttributeRoutes();

        // Convention-based routing.
        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
    }
}

并使用适当的属性和语法更新控制器

[RoutePrefix("api/SyncPersonnelViaAwsApi")]
public class SyncPersonnelViaAwsApiController : ApiController {

    //GET api/SyncPersonnelViaAwsApi/4
    [HttpGet]
    [Route("{id:int}")]
    public IHttpActionResult Get(int id) {
        return Ok("value");
    }

    //POST api/SyncPersonnelViaAwsApi
    [HttpPost]
    [Route("")]
    public IHttpActionResult SapCall([FromBody]string xmlFile) {
        string responseMsg = "Failed Import User";

        if (!IsNewestVersionOfXMLFile(xmlFile)) {
            responseMsg = "Not latest version of file, update not performed";
        } else {
            Business.PersonnelReplicate personnelReplicate = BusinessLogic.SynchronisePersonnel.BuildFromDataContractXml<Business.PersonnelReplicate>(xmlFile);
            bool result = Service.Personnel.SynchroniseCache(personnelReplicate);
            if (result) {
                responseMsg = "Success Import Sap Cache User";
            }
        }

        var data = new { 
            response = responseMsg,
            isNewActiveDirectoryUser = false
        };

        Ok(data);
    }
}

记下动作上方 cmets 中的预期路径。

[Http{Verb}] 属性告诉路由框架哪些请求可以映射到操作。

现在从客户端调用的路径将是

GET api/SyncPersonnelViaAwsApi/4
POST api/SyncPersonnelViaAwsApi

正如 cmets 中已经提到的,端口 80 不用于 HTTP 调用。甚至更新问题中的链接示例也使用端口 443 进行 HTTPS 调用。 options 中的标头显示 JSON,但 body 推断正在发送 XML。

var post_options = {
    host: 'actualUrlAddress',
    protocol: 'https',
    port: '443',
    path: '/api/SyncPersonnelViaAwsApi',
    method: 'POST',
    headers: {
        'Content-Type': 'application/xml',
        'Content-Length': post_data.length
    }
};

为了让客户端成功与 Web API 通信,客户端需要确保它发出的请求有效。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-08-25
    • 2019-04-29
    • 2020-03-01
    • 2020-08-12
    • 2016-02-27
    • 2017-03-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多