如何将 json 从 icecast 获取到反应组件中?

Posted

技术标签:

【中文标题】如何将 json 从 icecast 获取到反应组件中?【英文标题】:How to get json from icecast into react component? 【发布时间】:2017-03-18 14:38:47 【问题描述】:

我一直在试图弄清楚为什么这个 json 对我没有好处。根据 jsonlint,它的 json 无效。如何将其转换为有效的 json?我试过使用 fetch 和 xhr。我正在解决 cors 问题,现在我很难过。我已经搜索过,但不确定我是否找到了类似的东西。

我的 react 组件方法:

  fetchData() 

      var url = 'http://192.168.1.10:8000/status-json.xsl'
      var self = this;
      fetch(url, 
          'mode': 'no-cors'
      )
          .then(function(response) 
              return response.json()
          ).then(function(json) 
              console.log('parsed json', json)
          ).
      catch (function(ex) 
          console.log('parsing failed', ex)
      )
      xhr(
          url: url,
          dataType: 'jsonp',
          headers: 
              "Content-Type": "application/json",
              'Access-Control-Allow-Origin': "*"
          ,
      , function(err, data) 
          var body = JSON.parse(data);
          console.log(body)
          self.setState(
              data: body,
          );
      );
  ,

我的 icecast json。


icestats: 
admin: "",
host: "",
location: "",
server_id: "Icecast 2.4.1",
server_start: "Tue, 28 Jun 2016 14:41:06 -0500",
server_start_iso8601: "2016-06-28T14:41:06-0500",
source: [

audio_info: "bitrate=39",
bitrate: 39,
genre: "court",
listener_peak: 3,
listeners: 0,
listenurl: "http://192.168.1.10/RADIO-2nd-1",
server_description: "RADIO-2nd-1",
server_name: "RADIO-2nd-1",
server_type: "audio/mpeg",
server_url: "http://192.168.1.176:81",
stream_start: "Wed, 19 Oct 2016 17:06:24 -0500",
stream_start_iso8601: "2016-10-19T17:06:24-0500",
dummy: null
,

audio_info: "bitrate=75",
bitrate: 75,
genre: "court",
listener_peak: 0,
listeners: 0,
listenurl: "http://192.168.1.10/RADIO-2nd-2",
server_description: "RADIO-2nd-2",
server_name: "RADIO-2nd-2",
server_type: "audio/mpeg",
server_url: "http://192.168.1.176:82",
stream_start: "Wed, 12 Oct 2016 19:24:26 -0500",
stream_start_iso8601: "2016-10-12T19:24:26-0500",
dummy: null
,

audio_info: "bitrate=39",
bitrate: 39,
genre: "court",
listener_peak: 7,
listeners: 4,
listenurl: "http://192.168.1.10/RADIO-5th-1",
server_description: "RADIO-5th-1",
server_name: "RADIO-5th-1",
server_type: "audio/mpeg",
server_url: "http://192.168.1.83",
stream_start: "Wed, 19 Oct 2016 23:43:45 -0500",
stream_start_iso8601: "2016-10-19T23:43:45-0500",
dummy: null
,

audio_info: "bitrate=39",
bitrate: 39,
genre: "court",
listener_peak: 0,
listeners: 0,
listenurl: "http://192.168.1.10/RADIOBK-4th-1",
server_description: "RADIOBK-4th-1",
server_name: "RADIOBK-4th-1",
server_type: "audio/mpeg",
server_url: "http://192.168.1.10",
stream_start: "Wed, 02 Nov 2016 14:00:42 -0500",
stream_start_iso8601: "2016-11-02T14:00:42-0500",
dummy: null
,

audio_info: "bitrate=39",
bitrate: 39,
genre: "court",
listener_peak: 2,
listeners: 0,
listenurl: "http://192.168.1.10/RADIO-1st-1",
server_description: "RADIO-1st-1",
server_name: "RADIO-1st-1",
server_type: "audio/mpeg",
server_url: "http://156.127.4.72",
stream_start: "Tue, 18 Oct 2016 08:06:39 -0500",
stream_start_iso8601: "2016-10-18T08:06:39-0500",
dummy: null
,

audio_info: "bitrate=39",
bitrate: 39,
genre: "court",
listener_peak: 6,
listeners: 1,
listenurl: "http://192.168.1.10/RADIO-2nd-1",
server_description: "RADIO-2nd-1",
server_name: "RADIO-2nd-1",
server_type: "audio/mpeg",
server_url: "http://156.127.4.62",
stream_start: "Tue, 18 Oct 2016 09:56:00 -0500",
stream_start_iso8601: "2016-10-18T09:56:00-0500",
dummy: null
,

audio_info: "bitrate=39",
bitrate: 39,
genre: "court",
listener_peak: 3,
listeners: 0,
listenurl: "http://192.168.1.10/RADIO-3rd-1",
server_description: "RADIO-3rd-1",
server_name: "RADIO-3rd-1",
server_type: "audio/mpeg",
server_url: "http://156.127.82.80",
stream_start: "Wed, 12 Oct 2016 19:24:26 -0500",
stream_start_iso8601: "2016-10-12T19:24:26-0500",
dummy: null
,

audio_info: "bitrate=39",
bitrate: 39,
genre: "court",
listener_peak: 0,
listeners: 0,
listenurl: "http://192.168.1.10/RADIO-3rd-2",
server_description: "RADIO-3rd-2",
server_name: "RADIO-3rd-2",
server_type: "audio/mpeg",
server_url: "http://156.127.82.81",
stream_start: "Wed, 12 Oct 2016 19:24:26 -0500",
stream_start_iso8601: "2016-10-12T19:24:26-0500",
dummy: null

]


浏览器控制台出错:

index.js:216 OPTIONS http://192.168.1.10:8000/status-json.xsl net::ERR_EMPTY_RESPONSE_createXHR @ index.js:216createXHR @ index.js:50fetchData @ _template.jsx:139proxiedMethod @ createPrototypeProxy.js:44exports_render @ _template.jsx:433tryRender @ index.js:34proxiedMethod @ createPrototypeProxy.js:44(anonymous function) @ ReactCompositeComponent.js:793measureLifeCyclePerf @ ReactCompositeComponent.js:74_renderValidatedComponentWithoutOwnerOrContext @ ReactCompositeComponent.js:792_renderValidatedComponent @ ReactCompositeComponent.js:819performInitialMount @ ReactCompositeComponent.js:361mountComponent @ ReactCompositeComponent.js:257mountComponent @ ReactReconciler.js:47performInitialMount @ ReactCompositeComponent.js:370mountComponent @ ReactCompositeComponent.js:257mountComponent @ ReactReconciler.js:47performInitialMount @ ReactCompositeComponent.js:370mountComponent @ ReactCompositeComponent.js:257mountComponent @ ReactReconciler.js:47performInitialMount @ ReactCompositeComponent.js:370mountComponent @ ReactCompositeComponent.js:257mountComponent @ ReactReconciler.js:47performInitialMount @ ReactCompositeComponent.js:370mountComponent @ ReactCompositeComponent.js:257mountComponent @ ReactReconciler.js:47mountComponentIntoNode @ ReactMount.js:105perform @ Transaction.js:138batchedMountComponentIntoNode @ ReactMount.js:127perform @ Transaction.js:138batchedUpdates @ ReactDefaultBatchingStrategy.js:63batchedUpdates @ ReactUpdates.js:98_renderNewRootComponent @ ReactMount.js:321_renderSubtreeIntoContainer @ ReactMount.js:402render @ ReactMount.js:423(anonymous function) @ web-entry.js:79module.exports @ .gatsby-context.js:15(anonymous function) @ web-entry.js:69loadConfig @ web-entry.js:35(anonymous function) @ web-entry.js:68(anonymous function) @ bundle.js?t=1478278055741:2396__webpack_require__ @ bundle.js?t=1478278055741:554fn @ bundle.js?t=1478278055741:85(anonymous function) @ multi_main:2(anonymous function) @ bundle.js?t=1478278055741:584__webpack_require__ @ bundle.js?t=1478278055741:554(anonymous function) @ bundle.js?t=1478278055741:577(anonymous function) @ bundle.js?t=1478278055741:580
VM7812:1 Uncaught SyntaxError: Unexpected token o in JSON at position 1
    at JSON.parse (<anonymous>)
    at Object.eval [as callback] (webpack:///./_template.jsx?:147:23)
    at cbOnce (webpack:///../~/xhr/index.js?:62:21)
    at loadFunc (webpack:///../~/xhr/index.js?:138:16)
    at XMLHttpRequest.readystatechange (webpack:///../~/xhr/index.js?:68:13)

【问题讨论】:

【参考方案1】:

我认为问题在于像 icestats 这样的 JSON 键应该被引用:"icestats": ...

尝试用这个替换你的status-json.xsl

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:import href="xml2json.xslt"/>
<xsl:output indent="no" omit-xml-declaration="yes" method="text" encoding="UTF-8" media-type="application/json"/>
<xsl:strip-space elements="*"/>

<!-- override imported transform variable to enable output -->
<xsl:variable name="output">true</xsl:variable>

<!-- hide certain nodes from all sources -->
<xsl:template match="icestats/source/max_listeners" />
<xsl:template match="icestats/source/public" />
<xsl:template match="icestats/source/source_ip" />
<xsl:template match="icestats/source/slow_listeners" />
<xsl:template match="icestats/source/*[contains(name(), 'total_bytes')]" />
<xsl:template match="icestats/source/user_agent" >
    <!-- user_agent is most of the time the last node in a mount, 
         if we just delete it, then we will malform the output, 
         so special handling applies. -->
    <xsl:if test="following-sibling::*"></xsl:if>
    <xsl:if test="not(following-sibling::*)">"dummy":null</xsl:if> 
</xsl:template>

<!-- hide certain global nodes -->
<xsl:template match="icestats/sources" />
<xsl:template match="icestats/clients" />
<xsl:template match="icestats/stats" />
<xsl:template match="icestats/listeners" />
<xsl:template match="node()[contains(name(), 'connections')]" />

</xsl:stylesheet>

还将此文件xml2json.xslt 添加到 Icecast 网络目录:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="no" omit-xml-declaration="yes" method="text" encoding="UTF-8" media-type="application/json"/>
    <xsl:strip-space elements="*"/>
  <!--default to no output-->
  <xsl:variable name="output">false</xsl:variable>

  <!--constant-->
  <xsl:variable name="d">0123456789</xsl:variable>

  <!-- ignore document text -->
  <xsl:template match="text()[preceding-sibling::node() or following-sibling::node()]"/>

  <!-- string -->
  <xsl:template match="text()">
    <xsl:call-template name="escape-string">
      <xsl:with-param name="s" select="."/>
    </xsl:call-template>
  </xsl:template>

  <!-- Main template for escaping strings; used by above template and for object-properties 
       Responsibilities: placed quotes around string, and chain up to next filter, escape-bs-string -->
  <xsl:template name="escape-string">
    <xsl:param name="s"/>
    <xsl:text>"</xsl:text>
    <xsl:call-template name="escape-bs-string">
      <xsl:with-param name="s" select="$s"/>
    </xsl:call-template>
    <xsl:text>"</xsl:text>
  </xsl:template>

  <!-- Escape the backslash (\) before everything else. -->
  <xsl:template name="escape-bs-string">
    <xsl:param name="s"/>
    <xsl:choose>
      <xsl:when test="contains($s,'\')">
        <xsl:call-template name="escape-quot-string">
          <xsl:with-param name="s" select="concat(substring-before($s,'\'),'\\')"/>
        </xsl:call-template>
        <xsl:call-template name="escape-bs-string">
          <xsl:with-param name="s" select="substring-after($s,'\')"/>
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <xsl:call-template name="escape-quot-string">
          <xsl:with-param name="s" select="$s"/>
        </xsl:call-template>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <!-- Escape the double quote ("). -->
  <xsl:template name="escape-quot-string">
    <xsl:param name="s"/>
    <xsl:choose>
      <xsl:when test="contains($s,'&quot;')">
        <xsl:call-template name="encode-string">
          <xsl:with-param name="s" select="concat(substring-before($s,'&quot;'),'\&quot;')"/>
        </xsl:call-template>
        <xsl:call-template name="escape-quot-string">
          <xsl:with-param name="s" select="substring-after($s,'&quot;')"/>
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <xsl:call-template name="encode-string">
          <xsl:with-param name="s" select="$s"/>
        </xsl:call-template>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <!-- Replace tab, line feed and/or carriage return by its matching escape code. Can't escape backslash
       or double quote here, because they don't replace characters (&#x0; becomes \t), but they prefix 
       characters (\ becomes \\). Besides, backslash should be seperate anyway, because it should be 
       processed first. This function can't do that. -->
  <xsl:template name="encode-string">
    <xsl:param name="s"/>
    <xsl:choose>
      <!-- tab -->
      <xsl:when test="contains($s,'&#x9;')">
        <xsl:call-template name="encode-string">
          <xsl:with-param name="s" select="concat(substring-before($s,'&#x9;'),'\t',substring-after($s,'&#x9;'))"/>
        </xsl:call-template>
      </xsl:when>
      <!-- line feed -->
      <xsl:when test="contains($s,'&#xA;')">
        <xsl:call-template name="encode-string">
          <xsl:with-param name="s" select="concat(substring-before($s,'&#xA;'),'\n',substring-after($s,'&#xA;'))"/>
        </xsl:call-template>
      </xsl:when>
      <!-- carriage return -->
      <xsl:when test="contains($s,'&#xD;')">
        <xsl:call-template name="encode-string">
          <xsl:with-param name="s" select="concat(substring-before($s,'&#xD;'),'\r',substring-after($s,'&#xD;'))"/>
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise><xsl:value-of select="$s"/></xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <!-- number (no support for javascript mantissa) -->
  <xsl:template match="text()[not(string(number())='NaN' or
                       (starts-with(.,'0' ) and . != '0'))]">
    <xsl:value-of select="."/>
  </xsl:template>

  <!-- boolean, case-insensitive -->
  <xsl:template match="text()[translate(.,'TRUE','true')='true']">true</xsl:template>
  <xsl:template match="text()[translate(.,'FALSE','false')='false']">false</xsl:template>

  <!-- objects and arrays -->
  <xsl:template match="*" name="base">
    <xsl:choose>
      <!-- complete array -->
      <xsl:when test="(count(../*[name(current())=name()])=count(../*)) and count(../*[name(current())=name()])&gt;1">
        <xsl:variable name="el" select="name()"/>
        <xsl:if test="not(following-sibling::*[name()=$el])">
          <xsl:text>[</xsl:text>
          <xsl:for-each select="../*[name()=$el]">
            <xsl:if test="position()!=1">,</xsl:if>
            <xsl:choose>
              <xsl:when test="not(child::node())">
                <xsl:text>null</xsl:text>
              </xsl:when>
              <xsl:otherwise>
                <xsl:apply-templates select="child::node()"/>
              </xsl:otherwise>
            </xsl:choose>
          </xsl:for-each>
          <xsl:text>]</xsl:text>
        </xsl:if>
      </xsl:when>

      <!-- partial array -->
      <xsl:when test="count(../*[name(current())=name()])&gt;1">
        <xsl:if test="not(preceding-sibling::*)"></xsl:if>
        <xsl:variable name="el" select="name()"/>
        <xsl:if test="not(following-sibling::*[name()=$el])">
          <xsl:call-template name="escape-string">
            <xsl:with-param name="s" select="$el"/>
          </xsl:call-template>
          <xsl:text>:[</xsl:text>
          <xsl:for-each select="../*[name()=$el]">
            <xsl:if test="position()!=1">,</xsl:if>
            <xsl:choose>
              <xsl:when test="not(child::node())">
                <xsl:text>null</xsl:text>
              </xsl:when>
              <xsl:otherwise>
                <xsl:apply-templates select="child::node()"/>
              </xsl:otherwise>
            </xsl:choose>
          </xsl:for-each>
          <xsl:text>]</xsl:text>
          <xsl:if test="following-sibling::*">,</xsl:if>
        </xsl:if>
        <xsl:if test="not(following-sibling::*)"></xsl:if>
      </xsl:when>

      <!-- object -->
      <xsl:otherwise>
        <xsl:if test="not(preceding-sibling::*)"></xsl:if>
        <xsl:call-template name="escape-string">
          <xsl:with-param name="s" select="name()"/>
        </xsl:call-template>
        <xsl:text>:</xsl:text>
        <!-- check type of node -->
        <xsl:choose>
            <!-- null nodes -->
            <xsl:when test="count(child::node())=0">null</xsl:when>
            <!-- other nodes -->
            <xsl:otherwise>
                <xsl:apply-templates select="child::node()"/>
            </xsl:otherwise>
          </xsl:choose>
          <!-- end of type check -->
          <xsl:if test="following-sibling::*">,</xsl:if>
        <xsl:if test="not(following-sibling::*)"></xsl:if>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <!-- convert root element to an anonymous container -->
  <xsl:template match="/">
    <xsl:if test="$output='true'">
      <xsl:apply-templates select="node()"/>
    </xsl:if>
  </xsl:template>

</xsl:stylesheet>

请检查您的 JSON URL (http://192.168.1.10:8000/status-json.xsl) 是否正常工作,例如尝试在浏览器中打开它,因为此错误:

http://192.168.1.10:8000/status-json.xsl net::ERR_EMPTY_RESPONSE_createXHR

表示响应为空。

这是我的一个网络收音机中的一个工作示例,它不是 React (jQuery),但它应该可以工作。

注意:

    您不必解析响应 JSON.parse(data),因为返回的数据是 JSON 格式。 我的 Icecast 实例配置为使用此标头进行响应:
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Origin, Accept, X-Requested-With, Content-Type
Access-Control-Allow-Methods: GET, OPTIONS, HEAD

这允许我们绕过 CORS 限制。将此行添加到您的 Icecast 配置文件中:

<icecast>
    <http-headers>
        <header name="Access-Control-Allow-Origin" value="*" />
        <header name="Access-Control-Allow-Headers" value="Origin, Accept, X-Requested-With, Content-Type, If-Modified-Since" />
        <header name="Access-Control-Allow-Methods" value="GET, OPTIONS, HEAD" />
    </http-headers>
...

这是我的 sn-p(它输出当前曲目标题):

jQuery.get("http://stream.indiecore.fm:8000/status-json.xsl", , function(response)
  console.log("Now playing: ", response.icestats.source[0]['title']);
)
&lt;script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"&gt;&lt;/script&gt;

【讨论】:

感谢您的回复。我替换了 /etc/icecast2/web 中的 status-json2.xsl 并将 xml2json.xslt 添加到 web 文件夹中。我重启了服务器,json输出还是一样的。 我开始认为这个问题与“ERR_EMPTY_RESPONSE”有关。我可以确认文件存在并且可以在浏览器中查看。 更新了我的答案。 谢谢。使用 Jquery 确实可以解决它。这是一个可行的解决方案。我更喜欢使用 react fetch 来尝试获取这些数据。所以我会从这里开始工作。谢谢。

以上是关于如何将 json 从 icecast 获取到反应组件中?的主要内容,如果未能解决你的问题,请参考以下文章

如何在本机反应中从平面列表中设置 Json 数组

如何在反应中从json文件中获取数据?

如何在本机反应中从 json 获取数据?

如何使用 avformat (ffmpeg) 写入 Icecast 挂载点?

如何从网站获取 mp3 音频流 url?

如何插入 data.json 以使组件与界面中的所有属性(打字稿)发生反应