如何对 URL 进行 JSON 调用?

IT技术 javascript json
2021-01-30 18:29:24

我正在查看以下 API:

http://wiki.github.com/soundcloud/api/oembed-api

他们给出的例子是

称呼:

http://soundcloud.com/oembed?url=http%3A//soundcloud.com/forss/flickermood&format=json

回复:

{
"html":"<object height=\"81\" ... ",
"user":"Forss",
"permalink":"http:\/\/soundcloud.com\/forss\/flickermood",
"title":"Flickermood",
"type":"rich",
"provider_url":"http:\/\/soundcloud.com",
"description":"From the Soulhack album...",
"version":1.0,
"user_permalink_url":"http:\/\/soundcloud.com\/forss",
"height":81,
"provider_name":"Soundcloud",
"width":0
}

我需要做什么才能从 URL 中获取这个 JSON 对象?

6个回答

似乎他们js为格式参数提供了一个选项,它将返回 JSONP。您可以像这样检索 JSONP:

function getJSONP(url, success) {

    var ud = '_' + +new Date,
        script = document.createElement('script'),
        head = document.getElementsByTagName('head')[0] 
               || document.documentElement;

    window[ud] = function(data) {
        head.removeChild(script);
        success && success(data);
    };

    script.src = url.replace('callback=?', 'callback=' + ud);
    head.appendChild(script);

}

getJSONP('http://soundcloud.com/oembed?url=http%3A//soundcloud.com/forss/flickermood&format=js&callback=?', function(data){
    console.log(data);
});  
这个 getJSONP 方法是否适用于没有 html 行的 json 对象?
2021-03-19 18:29:24
由于帖子标题是 JSON,这个答案一开始让我感到困惑,我并没有立即意识到此代码示例返回 JSONP,它根本不是 JSON(因此无法读取格式正确的 JSON。)下面的答案来自@DickFeynman 应该被撞到这个上面,它工作得很好。这是一个显示 JSON 和 JSONP 之间差异的教程:web.archive.org/web/20160114013014/http : //...
2021-04-01 18:29:24
现代用户请注意:请注意此答案上的旧日期。由于现代浏览器安全功能,这不再起作用。在撰写本文时,在 Chrome 中,它会导致 CORB(不,不是 CORS)错误。
2021-04-03 18:29:24
这很好用,谢谢 JP!有趣的是 jquery 方法似乎不起作用......
2021-04-05 18:29:24

标准的 http GET 请求应该可以做到。然后就可以使用 JSON.parse() 把它变成一个 json 对象。

function Get(yourUrl){
    var Httpreq = new XMLHttpRequest(); // a new request
    Httpreq.open("GET",yourUrl,false);
    Httpreq.send(null);
    return Httpreq.responseText;          
}

然后

var json_obj = JSON.parse(Get(yourUrl));
console.log("this is the author name: "+json_obj.author_name);

基本上就是这样

给定的 URI 位于另一个域上,因此除非外部服务器发送 CORS 标头,否则正常的 AJAX 请求将不起作用。
2021-03-24 18:29:24
并不是说这是一个同步请求。恕我直言,这些是个坏主意,可以撑起整个网站。异步加载它们并传递成功函数要好得多。
2021-03-26 18:29:24
@CharlesClayton 你是怎么做到的?我发出的同步请求只会产生一个Network Error.
2021-04-09 18:29:24

由于 URL 与您的网站不在同一个域中,因此您需要使用 JSONP。

例如:(在 jQuery 中):

$.getJSON(
    'http://soundcloud.com/oembed?url=http%3A//soundcloud.com/forss/flickermood&format=js&callback=?', 
    function(data) { ... }
);

这通过创建一个<script>像这样标签来工作

<script src="http://soundcloud.com/oembed?url=http%3A//soundcloud.com/forss/flickermood&format=js&callback=someFunction" type="text/javascript"></script>

然后,他们的服务器发出 Javascript 调用someFunction要检索的数据。
`someFunction 是由 jQuery 生成的内部回调,然后调用您的回调。

仍然不高兴,在萤火虫控制台中,GET 请求是红色的,带有红色叉号(失败)
2021-03-19 18:29:24
怎么样header('Access-Control-Allow-Origin: *');
2021-03-26 18:29:24
@SLaks 是否有必要在 URL 中的某处添加“?callback=”?否则,getJSON 不会只是做一个普通的 XMLHttpRequest GET 吗?
2021-03-28 18:29:24
@Haroldo:是的;我忘记添加了&callback=?
2021-03-29 18:29:24
这不起作用: <script type="text/javascript"> $(function(){ $.getJSON(' soundcloud.com/oembed?url=http%3A//soundcloud.com/forss/... ', function (e) { $('body').append(e); alert(e); }); }) </script>
2021-04-09 18:29:24

在现代 JS 中,您可以通过fetch()在 URL 上调用 ES6 来获取 JSON 数据,然后使用 ES7从 fetch 中async/await“解压”响应对象以获取 JSON 数据,如下所示:

const getJSON = async url => {
  const response = await fetch(url);
  if(!response.ok) // check if response worked (no 404 errors etc...)
    throw new Error(response.statusText);

  const data = response.json(); // get JSON from the response
  return data; // returns a promise, which resolves to this data value
}

console.log("Fetching data...");
getJSON("https://soundcloud.com/oembed?url=http%3A//soundcloud.com/forss/flickermood&format=json").then(data => {
  console.log(data);
}).catch(error => {
  console.error(error);
});

如果忽略异常/错误处理,上述方法可以简化为几行(通常不推荐,因为这会导致不必要的错误):

const getJSON = async url => {
  const response = await fetch(url);
  return response.json(); // get JSON from the response 
}

console.log("Fetching data...");
getJSON("https://soundcloud.com/oembed?url=http%3A//soundcloud.com/forss/flickermood&format=json")
  .then(data => console.log(data));

简化的方法对我来说效果很好......
2021-03-14 18:29:24
(Nick) 如果我在控制台 ( $ node code.js) 而不是在任何给定的浏览器中运行您的代码,会有什么不同吗?
2021-03-20 18:29:24
直到我 import:npm install node-fetch并添加const fetch = require("node-fetch");到我的代码中此解决方案才对我有用
2021-03-25 18:29:24
这应该是新接受的答案。
2021-03-27 18:29:24
@carloswm85 是的,fetch它不像浏览器窗口那样适用于节点环境,因此需要手动安装。axios是另一个流行用于发出 HTTP 请求的包。
2021-04-01 18:29:24

DickFeynman 的回答是适用于 JQuery 不适合或不需要的任何情况的可行解决方案。正如 ComFreek 所指出的,这需要在服务器端设置 CORS 标头。如果这是您的服务,并且您可以处理更大的安全问题,那么这是完全可行的。

这是一个 Flask 服务列表,设置 CORS 标头,从数据库中获取数据,使用 JSON 响应,并在客户端愉快地使用 DickFeynman 的方法:

#!/usr/bin/env python 
from __future__ import unicode_literals
from flask      import Flask, Response, jsonify, redirect, request, url_for
from your_model import *
import os
try:
    import simplejson as json;
except ImportError:
    import json
try:
    from flask.ext.cors import *
except:
    from flask_cors import *

app = Flask(__name__)

@app.before_request
def before_request():
try:
    # Provided by an object in your_model
    app.session = SessionManager.connect()
except:
    print "Database connection failed."

@app.teardown_request
def shutdown_session(exception=None):
    app.session.close()

# A route with a CORS header, to enable your javascript client to access 
# JSON created from a database query.
@app.route('/whatever-data/', methods=['GET', 'OPTIONS'])
@cross_origin(headers=['Content-Type'])
def json_data():
    whatever_list = []
    results_json  = None
    try:
        # Use SQL Alchemy to select all Whatevers, WHERE size > 0.
        whatevers = app.session.query(Whatever).filter(Whatever.size > 0).all()
        if whatevers and len(whatevers) > 0:
            for whatever in whatevers:
                # Each whatever is able to return a serialized version of itself. 
                # Refer to your_model.
                whatever_list.append(whatever.serialize())
             # Convert a list to JSON. 
             results_json = json.dumps(whatever_list)
    except SQLAlchemyError as e:
        print 'Error {0}'.format(e)
        exit(0)

    if len(whatevers) < 1 or not results_json:
        exit(0)
    else:
        # Because we used json.dumps(), rather than jsonify(), 
        # we need to create a Flask Response object, here.
        return Response(response=str(results_json), mimetype='application/json')

if __name__ == '__main__':
    #@NOTE Not suitable for production. As configured, 
    #      your Flask service is in debug mode and publicly accessible.  
    app.run(debug=True, host='0.0.0.0', port=5001) # http://localhost:5001/

your_model 包含你的任何东西的序列化方法,以及数据库连接管理器(它可以忍受一点重构,但足以集中创建数据库会话,在更大的系统或模型/视图/控制架构中)。这恰好使用 postgreSQL,但也可以轻松使用任何服务器端数据存储:

#!/usr/bin/env python 
# Filename: your_model.py
import time
import psycopg2
import psycopg2.pool
import psycopg2.extras
from   psycopg2.extensions        import adapt, register_adapter, AsIs
from   sqlalchemy                 import update
from   sqlalchemy.orm             import *
from   sqlalchemy.exc             import *
from   sqlalchemy.dialects        import postgresql
from   sqlalchemy                 import Table, Column, Integer, ForeignKey
from   sqlalchemy.ext.declarative import declarative_base

class SessionManager(object):
    @staticmethod
    def connect():
        engine = create_engine('postgresql://id:passwd@localhost/mydatabase', 
                                echo = True)
        Session = sessionmaker(bind = engine, 
                               autoflush = True, 
                               expire_on_commit = False, 
                               autocommit = False)
    session = Session()
    return session

  @staticmethod
  def declareBase():
      engine = create_engine('postgresql://id:passwd@localhost/mydatabase', echo=True)
      whatever_metadata = MetaData(engine, schema ='public')
      Base = declarative_base(metadata=whatever_metadata)
      return Base

Base = SessionManager.declareBase()

class Whatever(Base):
    """Create, supply information about, and manage the state of one or more whatever.
    """
    __tablename__         = 'whatever'
    id                    = Column(Integer, primary_key=True)
    whatever_digest       = Column(VARCHAR, unique=True)
    best_name             = Column(VARCHAR, nullable = True)
    whatever_timestamp    = Column(BigInteger, default = time.time())
    whatever_raw          = Column(Numeric(precision = 1000, scale = 0), default = 0.0)
    whatever_label        = Column(postgresql.VARCHAR, nullable = True)
    size                  = Column(BigInteger, default = 0)

    def __init__(self, 
                 whatever_digest = '', 
                 best_name = '', 
                 whatever_timestamp = 0, 
                 whatever_raw = 0, 
                 whatever_label = '', 
                 size = 0):
        self.whatever_digest         = whatever_digest
        self.best_name               = best_name
        self.whatever_timestamp      = whatever_timestamp
        self.whatever_raw            = whatever_raw
        self.whatever_label          = whatever_label

    # Serialize one way or another, just handle appropriately in the client.  
    def serialize(self):
        return {
            'best_name'     :self.best_name,
            'whatever_label':self.whatever_label,
            'size'          :self.size,
        }

回想起来,我可能已经将任何对象序列化为列表,而不是 Python dict,这可能简化了它们在 Flask 服务中的处理,并且我可能在 Flask 实现中更好地分离了关注点(数据库调用可能不应该是内置的路由处理),但可以改善这一点,一旦你有你自己的开发环境中工作的解决方案。

另外,我并不是建议人们避免使用 JQuery。但是,如果 JQuery 不在图片中,出于某种原因或另一种原因,这种方法似乎是一个合理的选择。

无论如何,它都有效。

这是我在客户端中对 DickFeynman 方法的实现:

<script type="text/javascript">
    var addr = "dev.yourserver.yourorg.tld"
    var port = "5001"

    function Get(whateverUrl){
        var Httpreq = new XMLHttpRequest(); // a new request
        Httpreq.open("GET",whateverUrl,false);
        Httpreq.send(null);
        return Httpreq.responseText;          
    }

    var whatever_list_obj = JSON.parse(Get("http://" + addr + ":" + port + "/whatever-data/"));
    whatever_qty = whatever_list_obj.length;
    for (var i = 0; i < whatever_qty; i++) {
        console.log(whatever_list_obj[i].best_name);
    }
</script>

我不打算列出我的控制台输出,但我正在查看一长串whatever.best_name 字符串。

更重要的是:whatever_list_obj 可用于我的 javascript 命名空间中,无论我想用它做什么,......这可能包括使用 D3.js 生成图形,使用 OpenLayers 或 CesiumJS 映射,或者计算一些中间值没有特别需要住在我的 DOM 中。