Статические файлы JSON через CDN через JSONP

У меня есть большое количество статических/редко меняющихся данных в формате JSON. Чтобы повысить производительность моего приложения ASP.NET MVC, я хотел бы переместить их в CDN (Amazon Cloud Front).

Однако, когда я это делаю, срабатывает междоменная политика, и jQuery выполняет вызов метода HTTP OPTIONS вместо HTTP GET, а Amazon отклоняет запрос с ответом «403 Forbidden».

JSONP может быть способом обойти это, но, поскольку файлы являются статическими и в CDN, нет возможности обернуть JSON в пользовательскую функцию. Однако я могу воссоздать их с известным именем функции. Например:

{"LineDetails":{"LineNo":"3109","DbId":9 ....}}

Я могу сделать что-то вроде:

JsonWrapping({"LineDetails":{"LineNo":"3109","DbId":9 ....}});

Имя функции «JsonWrapping» будет одинаковым для всех файлов.

Может ли jQuery загружать данные JSON через JSONP, если они заключены в то же имя функции, что и показано выше? Мое прочтение jQuery JSONP заключается в том, что jQuery создает какое-то пользовательское имя функции одноразового использования для запроса JSONP. Можно ли это переопределить?

Спасибо за вашу помощь.


person Mike Weerasinghe    schedule 21.07.2010    source источник


Ответы (2)


Я только что узнал, что это как-то возможно. Я решил это так:

$(document).ready(function(){
    $.getJSON("http://example.com/staticjsonfile.json",function(data){
    //callback function isn't here
    }
});
function JsonWrapping(data){
    //It's really here
    alert(data);
}

Это не идеально, так как вы теряете привязку к событию, вызвавшему запрос Ajax. Поэтому требуется некоторый взлом. Тем не менее, это своего рода делает работу. Я был бы очень открыт для лучшего решения.

person Bart Vangeneugden    schedule 23.07.2010
comment
Я также нашел эту ссылку [mail-archive.com/jquery [email protected]/msg73370.html], в котором показано, как использовать $.getScript для загрузки скрипта. - person Mike Weerasinghe; 23.07.2010
comment
Смотрите мой ответ ниже; вы не хотите жестко кодировать свою функцию успеха в свой скрипт - jquery предоставляет средства для решения этой проблемы. - person Chris Moschini; 03.05.2012

Лучшая практика для jQuery JSONP

В документах для $.getJSON и $.ajax в разделе jsonp указано, что вы можете задать имя функции обратного вызова явно с помощью свойства конфигурации jsonpCallback. Итак, если вы хотите, чтобы JsonWrapping(...) была функцией, которую jquery ожидает внутри ответа jsonp, вы можете связать вещи следующим образом:

$.ajax({
    url: 'http://blah.com/blah.json'​​​​​​​​​​​​​​​​​​​​​​​​,
    dataType: 'jsonp',
    cache: true,
    jsonpCallback: 'JsonWrapping'
})
.done(function(r) {
    status.text('It worked.');
})
.fail(function (a, b, c) {
    status.text('It failed.');
});​​​​​​​​​​​​​​​​​​​​​​​​

В приведенном выше примере ожидаемая функция обратного вызова внутри ответа jsonp теперь имеет значение JsonWrapping(), которое jQuery выдаст для вас, ответит вызовом .done() выше и очистит после себя — намного чище, чем жесткое кодирование JsonWrapping на странице.

Опасности жесткого кодирования и предложений по именованию

Важно учитывать, что если вы планируете иметь много вызовов jsonp на одной странице, а ваши функции переноса jsonp жестко запрограммированы в файлах jsonp, вы должны, по крайней мере, изменить свою функцию переноса чем-то, например, именем файла. В противном случае вы создадите проблему асинхронности. Например, предположим, что у вас есть этот код:

function jsonp(url) {
    return $.ajax({
        url: url,
        dataType: 'jsonp'
        cache: true,
        jsonpCallback: 'JsonWrapping'
    });
}

jsonp('http://cdn.mine/one.jsonp')
.done(...);

jsonp('http://cdn.mine/two.jsonp')
.done(...);

Один из этих вызовов jsonp завершится раньше другого — невозможно узнать какой — и jQuery находится в невозможной ситуации, когда он не может знать, какой .done() вызывать для какого ответа. В результате вы получите некоторые загрузки страниц там, где они вызываются правильно, и некоторые страницы, где данные перекрещиваются. Решение состоит в том, чтобы изменить что-то вроде имени файла, например:

function jsonp(url, wrapper) {
    return $.ajax({
        url: url,
        dataType: 'jsonp'
        cache: true,
        jsonpCallback: wrapper
    });
}

jsonp('http://cdn.mine/one.jsonp', 'one')
.done(...);

jsonp('http://cdn.mine/two.jsonp', 'two')
.done(...);

Таким образом, ответ от two.jsonp должен выглядеть так:

two({...json object here...})

Как это работает

Вызов в начале этого ответа заставит jQuery запросить URL-адрес через GET следующим образом:

http://blah.com/blah.json?callback=JsonWrapping

И ожидайте этого в качестве ответа:

JsonWrapping({...object here...})

Я включил cache: true выше, потому что это на CDN, и поэтому, по-видимому, не должно меняться очень часто. Если вы опустите cache: true, jQuery вставит второй параметр строки запроса, предназначенный для очистки кеша, например:

http://blah.com/blah.json?callback=JsonWrapping&_=1365175172440

Что может испортить суть CDN. Цель второго параметра строки запроса — гарантировать, что данные не загружаются из кеша браузера, и, когда они попадают на сервер (в данном случае CDN), строка запроса уникальна, что означает, что она также разрушает свой кеш.

Вне вашего сценария, когда вы используете CDN, существуют ситуации, когда функциональность jQuery по умолчанию желательна: например, когда вы хотите имитировать функциональность POST для другого домена, не нарушая политику того же происхождения, jsonp с этой функцией очистки кеша может сделать это для вас.

Если сервер, с которым вы разговариваете, ожидает в строке запроса что-то отличное от «обратного вызова» для указания имени функции обратного вызова в ответе, вы можете использовать свойство конфигурации jsonp — например, jsonp: 'myname' даст вам:

http://blah.com/blah.json?myname=JsonWrapping
person Chris Moschini    schedule 03.05.2012
comment
На самом деле нет ничего невозможного в том, чтобы узнать, что сработает. Вы можете зарегистрировать глобальную переменную или переменную jquery function jsonp(url, wrapper) { $.jsonpData.TransactionCounter++; $.jsonpData.ActiveTransactions.push({id:$.jsonpData.TransActionCounter, runOnce: false}); return $.ajax({ url: url, dataType: 'jsonp' cache: true, jsonpCallback: wrapper }); } Просто обновите любые данные в функции обратного вызова и позвольте функции опроса отслеживать $.jsonpData.ActiveTransactions, продолжая, пока не достигнет значения false. Повторный опрос при каждом успехе AJAX - person Garet Claborn; 09.05.2017
comment
@GaretClaborn Это просто говорит о том, что вы оба бежали, а не о том, кто прибыл первым. Представьте себе 2 запроса: A начинается раньше B, но B иногда возвращается раньше A. Возможно, вы не учитываете тот факт, что некоторые полезные данные jsonp являются статическими. - person Chris Moschini; 10.05.2017
comment
хотя он не говорит вам, что было выполнено первым, вы можете добавить это, поместив временную метку в объект транзакции. что он делает, так это создает временную синхронизацию/барьер, чтобы ваша обработка происходила как если бы сумма пришла в том порядке, в котором она была отправлена. это особенно полезно для статических полезных нагрузок, которые не могут отслеживать такие данные на стороне сервера. - person Garet Claborn; 10.05.2017