Javascript 如何对 url 进行 JSON 调用?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2499567/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 00:39:25  来源:igfitidea点击:

How to make a JSON call to a url?

javascriptjson

提问by Haroldo

I'm looking at the following API:

我正在查看以下 API:

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

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

The example they give is

他们给出的例子是

Call:

称呼:

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

Response:

回复:

{
"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
}

What do I have to do to get this JSON object from just a url?

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

回答by James

It seems they offer a jsoption for the format parameter, which will return JSONP. You can retrieve JSONP like so:

似乎他们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);
});  

回答by DickFeynman

A standard http GET request should do it. Then you can use JSON.parse() to make it into a json object.

标准的 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;          
}

then

然后

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

that's basically it

基本上就是这样

回答by SLaks

Because the URL isn't on the same domain as your website, you need to use JSONP.

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

For example: (In jQuery):

例如:(在 jQuery 中):

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

This works by creating a <script>tag like this one:

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

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

Their server then emits Javascript that calls someFunctionwith the data to retrieve.
`someFunction is an internal callback generated by jQuery that then calls your callback.

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

回答by user3842054

DickFeynman's answer is a workable solution for any circumstance in which JQuery is not a good fit, or isn't otherwise necessary. As ComFreek notes, this requires setting the CORS headers on the server-side. If it's your service, and you have a handle on the bigger question of security, then that's entirely feasible.

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

Here's a listing of a Flask service, setting the CORS headers, grabbing data from a database, responding with JSON, and working happily with DickFeynman's approach on the client-side:

这是一个 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 contains the serialization method for your whatever, as well as the database connection manager (which could stand a little refactoring, but suffices to centralize the creation of database sessions, in bigger systems or Model/View/Control architectures). This happens to use postgreSQL, but could just as easily use any server side data store:

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,
        }

In retrospect, I might have serialized the whatever objects as lists, rather than a Python dict, which might have simplified their processing in the Flask service, and I might have separated concerns better in the Flask implementation (The database call probably shouldn't be built-in the the route handler), but youcan improve on this, once you have a working solution in your own development environment.

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

Also, I'm not suggesting people avoid JQuery. But, if JQuery's not in the picture, for one reason or another, this approach seems like a reasonable alternative.

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

It works, in any case.

无论如何,它都有效。

Here's my implementation of DickFeynman's approach, in the the client:

这是我在客户端中对 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>

I'm not going to list my console output, but I'm looking at a long list of whatever.best_name strings.

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

More to the point: The whatever_list_obj is available for use in my javascript namespace, for whateverI care to do with it, ...which might include generating graphics with D3.js, mapping with OpenLayers or CesiumJS, or calculating some intermediate values which have no particular need to live in my DOM.

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

回答by Quentin

You make a bog standard HTTP GET Request. You get a bog standard HTTP Response with an application/json content type and a JSON document as the body. You then parse this.

您发出一个沼泽标准 HTTP GET 请求。您将获得一个带有 application/json 内容类型和一个 JSON 文档作为正文的沼泽标准 HTTP 响应。然后你解析这个。

Since you have tagged this 'JavaScript' (I assume you mean "from a web page in a browser"), and I assume this is a third party service, you're stuck. You can't fetch data from remote URI in JavaScript unless explicit workarounds (such as JSONP) are put in place.

由于您已标记此“JavaScript”(我假设您的意思是“来自浏览器中的网页”),并且我假设这是第三方服务,因此您被卡住了。除非采取了明确的解决方法(例如 JSONP),否则您无法在 JavaScript 中从远程 URI 获取数据。

Oh wait, reading the documentation you linked to - JSONP is available, but you must say 'js' not 'json' and specify a callback: format=js&callback=foo

哦等等,阅读您链接到的文档 - JSONP 可用,但您必须说 'js' 而不是 'json' 并指定一个回调:format=js&callback=foo

Then you can just define the callback function:

然后你可以定义回调函数:

function foo(myData) { 
    // do stuff with myData
}

And then load the data:

然后加载数据:

var script = document.createElement('script');
script.type = 'text/javascript';
script.src = theUrlForTheApi;
document.body.appendChild(script);

回答by Nick Parsons

In modern-day JS, you can get your JSON data by calling ES6's fetch()on your URL and then using ES7's async/awaitto "unpack" the Responseobject from the fetch to get the JSON data like so:

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

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

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

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);
});