【问题标题】:How to send HTTP SOAP request to local Sonos device with NodeMCU?如何使用 NodeMCU 向本地 Sonos 设备发送 HTTP SOAP 请求?
【发布时间】:2017-06-13 08:48:13
【问题描述】:

如何在 Lua 中向我的 Sonos 扬声器发送一个简单的 HTTP POST/GET SOAP 请求?

我已经成功尝试了简单的 HTTP POST 和 GET 请求,但我不知道从哪里开始使用 SOAP 请求。

注意:我是这方面的新手。我以前从未使用过 NodeMCU,也没有在 Lua 中编程过。不过我有其他语言的经验。

我知道如何用 C#、Java 和 PHP 做到这一点。

这适用于邮递员:

HTTP 标头:

SOAPAction:urn:schemas-upnp-org:service:AVTransport:1#Pause
Content-Type:text/xml; charset="utf-8"
Host:192.168.0.10:1400

身体:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:Pause xmlns:u="urn:schemas-upnp-org:service:AVTransport:1"><InstanceID>0</InstanceID></u:Pause></s:Body></s:Envelope>

我做的是这个,它不起作用:

        sendRequest("192.168.0.10")
function sendRequest(url)
    print("Sending request to Sonos Playbar...")
    sk = net.createConnection(net.TCP, 0)
    sk:on("receive", function(sck, c) print(c) end )
    sk:on("connection", function(sck, c)

        print("\r\n\r\n\r\n")

        -- HTTP 405: Method not allowed
        -- sck:send("POST / HTTP/1.1\r\nHost: "..url..":1400\r\nConnection: keep-alive\r\nAccept: */*\r\n\r\n")

        -- HTTP 500, UPnP 402: Invalid arguments
        -- sck:send("POST /MediaRenderer/AVTransport/Control HTTP/1.1\r\nHost: "..url..":1400\r\nSOAPAction:urn:schemas-upnp-org:service:AVTransport:1#Pause\r\nConnection: keep-alive\r\n\r\nAccept: */*\r\n\r\n")


        local content = nil;
    content = "POST /MediaRenderer/AVTransport/Control\r\n"
    content = content.."Host:192.168.0.10:1400\r\n"
    content = content.."Content-Type:text/xml; charset=utf-8\r\n"
    content = content.."SOAPAction:urn:schemas-upnp-org:service:AVTransport:1#Pause\r\n"
    content = content.."\r\n"

    -- SOAP Body
    content = content.."<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\""
    content = content.." s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
    content = content.."<s:Body>"
    content = content.."<u:Pause xmlns:u=\"urn:schemas-upnp-org:service:AVTransport:1\">"
    content = content.."<InstanceID>0</InstanceID>"
    content = content.."</u:Pause>"
    content = content.."</s:Body>"
    content = content.."</s:Envelope>"
    -- SOAP Body End

        print(content.."\r\n\r\n\r\n")

        sck:send(content);
    end)
    sk:connect(1400, url)
end

我收到了我的 Sonos 播放器的回复:

HTTP/1.1 500 Internal Server Error
CONTENT-LENGTH: 347
CONTENT-TYPE: text/xml; charset="utf-8"
EXT: 
Server: Linux UPnP/1.0 Sonos/34.16-37101 (ZPS9)
Connection: close

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
    <s:Body>
        <s:Fault>
            <faultcode>s:Client</faultcode>
                <faultstring>UPnPError</faultstring>
                    <detail>
                        <UPnPError xmlns="urn:schemas-upnp-org:control-1-0">
                            <errorCode>401</errorCode>
                        </UPnPError>
                    </detail>
        </s:Fault>
    </s:Body>
</s:Envelope>

我做错了什么?基本上,我复制并粘贴了文本。也许是标题的顺序?也许我在声明标题错误之类的?

【问题讨论】:

  • 你能链接到 Sonos Api 文档吗?
  • 这里是 Sonos Api 文档的链接,但我宁愿只是向我本地的 Sonos 设备发送一个普通的 SOAP 请求,因为这也适用于其他编程语言(C#、Java、PHP)和设置API 是一条很长的路要走... musicpartners.sonos.com/?q=docs
  • 您能否使用 Postman 之类的 API 工具(独立于您的 IoT 堆栈)让请求正常工作?这是第一步。
  • 只是简单地环顾四周,我没有看到您发送带有 XML 的 POST 正文。我认为这是它工作所必需的。 SOAP 是一种基于 XML 的协议。例如。 hirahim.com/blog/2012/04/29/dissecting-the-sonos-controller
  • 亚当 B 正确。现在我已经从我的 C# 应用程序中复制了 SOAP 主体(工作正常),但它仍然给我上面的错误。它使用邮递员工作。当我将 Postman 中的内容复制并粘贴到 ESplorer(NodeMCU 的 IDE)时,它不起作用。

标签: http post soap nodemcu sonos


【解决方案1】:

我没有可玩的 Sonos 设备。因此,这不是一个已确认的答案。

content 变量中的字符串不是有效的 HTTP 请求。 Sonos 不理解为error code 401 means "invalid action"

您需要带有 \r\n 的单独 HTTP 标头。额外的\r\n 需要放在 HTTP 正文之前。因此,我希望您的 content 应该是:

"POST http://192.168.0.10:1400/MediaRenderer/AVTransport/Control\r\n
SOAPAction:urn:schemas-upnp-org:service:AVTransport:1#Pause\r\n
Content-Type:text/xml; charset=\"utf-8\"\r\n
Host:192.168.0.10:1400\r\n\r\n
<s:Envelope xmlns:s=\"http://schemas.xml......"

【讨论】:

  • 感谢您的回答,但不幸的是它也不起作用
  • 不要认为这是个人的,但我现在对您帖子中某些陈述的正确性有一定的怀疑。您显然使用我在此处提供的输入更新了帖子中的代码。如果原来的代码被复制粘贴到这里,你为什么还要修改它?
  • 无论如何我都会尝试使用http module发送这个HTTP POST。
  • 嗨,马塞尔,感谢您的回复。我更改(编辑)代码的原因是因为我仍在尝试它,并且我不希望任何人说我已经尝试过的代码中的错误。你知道我的意思吗?
  • 我肯定会尝试使用 HTTP 模块
【解决方案2】:

终于!我有它的工作!下面是让它工作的代码:

sendRequest("192.168.0.10")
function sendRequest(url)
    print("Sending request to Sonos Playbar...")
    local content = nil;
    content = "";
    -- SOAP Body
    content = content.."<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\""
    content = content.." s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
    content = content.."<s:Body>"
    content = content.."<u:Pause xmlns:u=\"urn:schemas-upnp-org:service:AVTransport:1\">"
    content = content.."<InstanceID>0</InstanceID>"
    content = content.."</u:Pause>"
    content = content.."</s:Body>"
    content = content.."</s:Envelope>"
    -- SOAP Body End

    http.post("http://"..url..":1400/MediaRenderer/AVTransport/Control",
        'Content-Type: text/xml; charset="utf-8"\r\n'..
        'Host:'..url..':1400\r\n'..
        'SOAPAction:urn:schemas-upnp-org:service:AVTransport:1#Pause\r\n',
        content, function(code, data)
            if(code < 0) then
                print("HTTP request failed with code "..code)
            else
                print(code, data)
            end
        end)
end

【讨论】:

  • 看起来和我在你还在使用 net 模块时所建议的完全一样。另请注意,您不需要带有 HTTP 模块的 Host HTTP 标头。它会根据 URL 自动生成。
猜你喜欢
  • 2019-08-21
  • 2018-12-04
  • 2018-01-27
  • 1970-01-01
  • 2012-08-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多