Статические файлы 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. Может ли это быть отменено?

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

Ответ 1

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

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

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

Ответ 2

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

В документах для $.getJSON и $.ajax секция jsonp отмечает, что вы можете явно задать имя функции обратного вызова с помощью jsonpCallback config. Поэтому, если вы хотите, чтобы 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. Цель второго параметра querystring состоит в том, чтобы гарантировать, что данные не загружаются из кеша браузера, и когда он попадает на сервер (в этом случае CDN), запрос вызывает уникальное значение, так как он также разбивает свой кеш.

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

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

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