2010-03-23 15 views
28

Busco en la siguiente API:¿Cómo hacer una llamada JSON a una url?

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

El ejemplo que dan es

Llamar:

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

Respuesta:

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

Qué hacer yo tiene que hacer para obtener este objeto JSON desde solo una url?

Respuesta

42

parece que ofrecen una opción para el formato js PARAMET er, que devolverá JSONP. Puede recuperar JSONP como lo siguiente:

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

esto funciona perfectamente, gracias J-P! interesante que los métodos jquery no parecían funcionar ... – Haroldo

+0

¿este método getJSONP funciona para un objeto json sin la fila html? – Lisa

+0

Esta respuesta me sorprendió al principio ya que el título del post es JSON, y no me di cuenta de inmediato que este ejemplo de código devuelve JSONP, que no es JSON en absoluto (y por lo tanto no leería correctamente el formato JSON) La respuesta a continuación de @DickFeynman se debe superar por encima de esta, funciona perfectamente. Aquí hay un tutorial que muestra las diferencias entre JSON y JSONP: https://web.archive.org/web/20160114013014/http://json-jsonp-tutorial.craic.com/index.html – ashleedawg

9

Debido a que la dirección no está en el mismo dominio que su sitio web, es necesario utilizar JSONP.

Por ejemplo: (En jQuery):

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

Esto funciona mediante la creación de una etiqueta <script> como éste:

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

Su servidor entonces emite Javascript que llama someFunction con los datos para recuperar .
`someFunction es una devolución de llamada interna generada por jQuery que luego llama a su devolución de llamada.

+1

genial lo intentaré, ¡gracias! – Haroldo

+1

@SLaks ¿no es necesario agregar "? Callback =" en algún lugar de la URL? De lo contrario, ¿no conseguirá JSON simplemente un XMLHttpRequest GET ordinario? – Pointy

+0

@Pointy: tienes razón; Olvidé. – SLaks

4

le hará un hotelucho estándar de solicitud HTTP GET. Obtienes una Respuesta HTTP estándar de pantano con un tipo de contenido application/json y un documento JSON como cuerpo. A continuación, analiza esto.

Puesto que usted ha marcado esta 'JavaScript' (supongo que quiere decir "de una página web en un navegador"), y supongo que este es un servicio de terceros, le pegan. No puede obtener datos del URI remoto en JavaScript a menos que se implementen soluciones temporales explícitas (como JSONP).

Oh, espera, la lectura de la documentación se ha vinculado a - JSONP está disponible, pero hay que decir 'js' no 'json' y especifique una devolución de llamada: format = js & devolución de llamada = foo

A continuación, puede simplemente definir la función de devolución de llamada:

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

y luego cargar los datos:

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

hay una opción JSONP (afortunadamente!) – Haroldo

28

Una solicitud http GET estándar debería hacerlo. Luego puede usar JSON.parse() para convertirlo en un objeto json.

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

continuación

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

que es básicamente

+1

El URI dado es en otro dominio, las solicitudes AJAX normales no funcionarán a menos que el servidor externo envíe encabezados CORS. – ComFreek

+1

No es que se trate de solicitudes sincrónicas. En mi humilde opinión, estas son una mala idea y pueden contener todo el sitio web. Es mucho mejor cargarlos de forma asincrónica y pasar una función de éxito. –

6

respuesta de DickFeynman es una solución viable para cualquier circunstancia en la que jQuery no es un buen ajuste, o no se indique lo contrario. Como señala ComFreek, esto requiere configurar los encabezados CORS en el lado del servidor.Si es su servicio, y tiene un control sobre la gran cuestión de la seguridad, entonces eso es totalmente factible.

Aquí hay una lista de un servicio Frasco, el establecimiento de los encabezados CORS, tomando datos de una base de datos, respondiendo con JSON, y trabajar felizmente con el enfoque de DickFeynman en el lado del cliente:

#!/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 contiene la serialización método para lo que sea, así como el administrador de conexión de base de datos (que podría soportar una pequeña refactorización, pero es suficiente para centralizar la creación de sesiones de base de datos, en sistemas más grandes o arquitecturas Modelo/Vista/Control). Esto sucede a usar PostgreSQL, pero sólo podía utilizar la misma facilidad cualquier almacén de datos del lado del servidor:

#!/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:[email protected]/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:[email protected]/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, 
     } 

En retrospectiva, podría haber serializado los cualesquiera que sean los objetos como listas, en lugar de un diccionario de Python, que podría haber simplificado su procesamiento en el servicio Flask, y podría haber separado las preocupaciones en la implementación de Flask (la llamada a la base de datos probablemente no debería estar incorporada en el controlador de ruta), pero usted puede mejorar esto, una vez que tenga una solución de trabajo en su propio entorno de desarrollo.

Además, no estoy sugiriendo que la gente evite JQuery. Pero, si JQuery no está en la imagen, por una razón u otra, este enfoque parece una alternativa razonable.

Funciona, en cualquier caso.

Aquí está mi aplicación del enfoque de DickFeynman, en el que el cliente:

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

que no voy a enumerar mi salida de la consola, pero estoy buscando a una larga lista de cadenas whatever.best_name.

Más al punto: La whatever_list_obj está disponible para su uso en mi espacio de nombres Javascript, por lo me importa que ver con eso, ... que pueden incluir gráficos generadores con D3.js, mapeo con OpenLayers o CesiumJS, o calculando algunos valores intermedios que no tienen ninguna necesidad particular de vivir en mi DOM.

Cuestiones relacionadas