如何将 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,'"')">
<xsl:call-template name="encode-string">
<xsl:with-param name="s" select="concat(substring-before($s,'"'),'\"')"/>
</xsl:call-template>
<xsl:call-template name="escape-quot-string">
<xsl:with-param name="s" select="substring-after($s,'"')"/>
</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 (� 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,'	')">
<xsl:call-template name="encode-string">
<xsl:with-param name="s" select="concat(substring-before($s,'	'),'\t',substring-after($s,'	'))"/>
</xsl:call-template>
</xsl:when>
<!-- line feed -->
<xsl:when test="contains($s,'
')">
<xsl:call-template name="encode-string">
<xsl:with-param name="s" select="concat(substring-before($s,'
'),'\n',substring-after($s,'
'))"/>
</xsl:call-template>
</xsl:when>
<!-- carriage return -->
<xsl:when test="contains($s,'
')">
<xsl:call-template name="encode-string">
<xsl:with-param name="s" select="concat(substring-before($s,'
'),'\r',substring-after($s,'
'))"/>
</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()])>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()])>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']);
)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
【讨论】:
感谢您的回复。我替换了 /etc/icecast2/web 中的 status-json2.xsl 并将 xml2json.xslt 添加到 web 文件夹中。我重启了服务器,json输出还是一样的。 我开始认为这个问题与“ERR_EMPTY_RESPONSE”有关。我可以确认文件存在并且可以在浏览器中查看。 更新了我的答案。 谢谢。使用 Jquery 确实可以解决它。这是一个可行的解决方案。我更喜欢使用 react fetch 来尝试获取这些数据。所以我会从这里开始工作。谢谢。以上是关于如何将 json 从 icecast 获取到反应组件中?的主要内容,如果未能解决你的问题,请参考以下文章