20.09.2013

JS. Как закодировать символы для адресной строки

encodeURIComponent()

Для того, чтобы закодировать параметр, который вы хотите передать в адресной строке используйте функцию:

param1 = encodeURIComponent("http://xyz.com/?a=12&b=55")

Затем вы можете создать URL наподобие такого:

url = "http://domain.com/?param1=" + param1 + "&param2=99";

Результат:

http://www.domain.com/?param1=http%3A%2F%2Fxyz.com%2F%Ffa%3D12%26b%3D55&param2=99

11.09.2013

Кроссдоменные запросы при помощи easyXDM

Существует отличный плагин easyXDM, который, используя наиболее подходящий транспорт, манипулирует запросами между разными доменами или поддоменами.

Документация:
http://easyxdm.net - официальный сайт плагина
http://habrahabr.ru/post/120336/ - статья на Хабре
https://github.com/oyvindkinsey/easyXDM - директория на GitHub
Этого мне хватило, чтобы разобраться, как без особых проблем отправлять POST-запросы на API, находящийся на поддомене.

Тест кроссбраузерной авторизации
<form id="myForm" method="POST">
    <div>
        <input type="text" id="name" name="Name" class="k-textbox" />
    </div>
    <div>
        <input type="text" id="password" name="Password" class="k-textbox" />
    </div>
    <input type="submit" value="Отправить" class="k-button" />
</form>
<script>
   
    $('#myForm').ajaxForm({
        beforeSubmit: function (arr, form, options) {
            //if (options.url.indexOf(location.host) < 0) { // если хост удаленный то используем наш метод
            var json = {};
            for (var i = 0; i < arr.length; i++) { // преобразуем сериализованные данные формы в нормальный объект js готовый к нашей сериализации (сама форма их передает в весьма странном виде)
                json[arr[i].name] = btoa(arr[i].value);
            }
            rpc.request({
                    // шлем кросс доменный запрос, подставляя наши параметры
                    url: apiRoute + "auth",
                    method: "POST",
                    data: json,
                    headers: {
                        'RequestVerificationToken': token
                    }
                }, function (response) {
                    alert('Success');
                }, function (response) {
                    alert('Error\n' + response.message);
                    return false;
                });
            return false; //останавливаем нативный ajax запрос от jQ
            //}
            //return false;
        }
    });

    var rpc = new easyXDM.Rpc({
            remote: apiRoute + "Scripts/EasyXDM"
        },
        {
            local: {
                request: {}
            },
            remote: {
                request: {}
            }
        });
</script>

28.08.2013

Если IE < 10 не хочет отправлять кроссдоменные запросы

Ситуация возникла после того, как проект был задеплоен на сервер. Прикол в том, что на IIS Express 8 и на IIS 7.5, установленные на локальной машине, все успешно работало. Запросы к API, размещенному на другом домене шли без проблем. Однако после выкладки на сервер IE 9 просто не слал ajax-запросы.

Проблему решил небольшой js, который посчастливилось найти на просторах интернета.
https://github.com/Malvolio/ie.xhr

Но стоит учесть, что он преобразует запрос в формат XDomainRequest, который в свою очередь имеет кучу ограничений. Например, нельзя присоединить к реквесту собственный хидер. Весь перечень ограничений легко можно найти в интернете — изучая материал, сто раз на него натыкался.


27.08.2013

JSONP Formatter для Web API

Для того, чтобы Web API отдавал данные в формате JSONP, необходимо:

1) установить package, прописав в Package Manager Console такую команду:
 Install-Package WebApiContrib.Formatting.Jsonp

2) в папку проекта App_Start добавить файл, содержащий следующий код:
public class FormatterConfig
    {
        public static void RegisterFormatters(MediaTypeFormatterCollection formatters)
        {
            var jsonFormatter = formatters.JsonFormatter;
            jsonFormatter.SerializerSettings = new JsonSerializerSettings
            {
                ContractResolver = new CamelCasePropertyNamesContractResolver()
            };
 
            // Insert the JSONP formatter in front of the standard JSON formatter.
            var jsonpFormatter = new JsonpMediaTypeFormatter(formatters.JsonFormatter);
            formatters.Insert(0, jsonpFormatter);
        }
    }

SerializerSettings  здесь исключительно для того, что задать правила именования свойств, поэтому по сути достаточно последних двух строк

3) зарегистрировать наш новый форматтер в Global.asax, добавив в метод Application.Start следующую строку: 

FormatterConfig.RegisterFormatters(GlobalConfiguration.Configuration.Formatters);


Предварительно необходимо, чтоб Web API был настроен на передачу JSON.
Для этого в WebApi.Register необходимо добавить две строки:


config.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);
config.Formatters.Add(GlobalConfiguration.Configuration.Formatters.JsonFormatter);

20.08.2013

Кроссдоменный обмен данными между Web API и Web Application

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

И вот настало время внедрять мой Web API в основной проект, он же сайт. Сразу оговорюсь, что в API была заложена защита, как же без нее. Авторизацию реализовал при помощи встроенной Forms Authentication. Также была внедрена защита от поддельных запросов с других сайтов или Preventing Cross-Site Request Forgery (CSRF) Attacks. То есть каждый входящий запрос проверялся на наличие валидного RequestVerificationToken. Проблемы начались, когда пришло время авторизовываться.

В ходе долгих странствий по интернету, было выяснено:

для того, что отправить авторизационные куки с одного домена на другой, требуется в запросе (будь то ajax, get или post) указывать следующий параметр:

xhrFields: {
    withCredentials: true
},

Ок, API успешно записывает куки в Response и при обратном запросе к API они присоединяются. Но все это добро работало лишь в Chrome. Ни в Mozilla FF, ни в IE 9 кроссдоменный обмен данными не шел.

Еще полдня на бесконечных просторах мировой паутины и решение найдено:

для FF требовалось на стороне API добавить в WebApiConfig в метод Register вот эти строки:
var cors = new EnableCorsAttribute(домен сайта, "*", "*");
config.EnableCors(cors);

для IE требовалось в скрипте страницы дописать строку:
jQuery.support.cors = true;

Решение не ахти какое, но рабочее.
Добавлено спустя некоторое время: решение работает только на localhost (: