【问题标题】:How to get json from icecast into react component?如何将 json 从 icecast 获取到反应组件中?
【发布时间】: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)

【问题讨论】:

    标签: json reactjs xmlhttprequest cors fetch


    【解决方案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),但它应该可以工作。

    注意:

    1. 您不必解析响应 JSON.parse(data),因为返回的数据是 JSON 格式。
    2. 我的 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 来尝试获取这些数据。所以我会从这里开始工作。谢谢。
    猜你喜欢
    • 2020-02-04
    • 2018-05-02
    • 1970-01-01
    • 2017-05-11
    • 1970-01-01
    • 2019-03-01
    • 2018-07-11
    • 2020-03-19
    • 1970-01-01
    相关资源
    最近更新 更多