Javascript i wysyłanie POST „w locie”

Dzisiaj podzielę się kolejnym skryptem jaki musiałem napisać w pracy. Wcześniej opisałem mały skrypt sprawdzający pozycję w wyszukiwarce Google. Funkcjonalność poprzedniego skryptu można (i my tak również robimy) uzyskać na wielu stronach SEO/SEM. Ten opisany tutaj musiał realizować pewne zadania na naszej stronie.

W jednym z naszych serwisów wrzucamy applet logowania do innego w innej domenie. Zazwyczaj nie było problemu wrzucaliśmy w jednym z widgetów iframe z adresem strony logowania i wszystko grało i huczało. W pewnym momencie dla kolejnego klienta iframe w FF pozostawał biały.  Myślę, błędny adres albo opcje widgetu źle ustawione. Sprawdzam wszystko OK. Porównuje kod z poprzednimi taki sam, sprawdzam na testowym panelu logowania działa. Nic to ticket do Service Desku niech się męczą co tam znowu nie działa we frameworku ale dalej grzebie samemu. Może FF coś spartolił otwieram więc stronę w IE dostaje komunikat, że ustawienia bezpieczeństwa nie pozwalają na wyświetlenie ramki. Oho to dało mi kierunek poszukiwań od razu w stronę Same-Origin Policy, a dokładniej X-Frame-Options. Uruchamiam LiveHTTP Headers sprawdzam nagłówki i zgadza się. Przy odwołaniu do panelu logowania (na innej domenie) dostaje odpowiedź DENY. Luzik szybki mail do Service Desku gdzie leży problem i jak go rozwiązać.

Wydawało mi się, że najłatwiej ustawić ALLOW-FROM i dodać naszą domenę. Dostaję odpowiedź, że nie da rady, zdziwienie, w końcu to nasza jest matczyną „główną” domeną. Nic to nie chcą, nie ma sprawy jedziemy szukać rozwiązania, w końcu za to mi płacą. Drugie najprostsze rozwiązanie to wklepać formant z logowaniem. Wstukałem, z CSSa nawet identycznie ostylowałem, a niech nie widzą różnicy. Sprawdzam wszystko ładnie wygląda ale dla pewności sprawdzam na innych przeglądarkach Opera i Chrome wyświetla idealnie na IE kaszana. Obrazek tła wyświetla się dwa razy, drugi w jakimś poronionym miejscu na stronie włążąc na inny widget O.o

Następnego dnia szkic strony miał być przedstawiony klientowi choćby z testowym logowaniem ale próbuję rozwiązać problem. Skoro IE źle wyświetla to w IE edytuje. Usuwam najpierw style. może coś sknociłem, ale nie dalej wywala. dodatkowo blokuje mi edycje strony (upss! po raz pierwszy). Wracam na FF usuwam zmiany, dalej źle wyświetla ale edycja działa (uff). Wywalam powoli kolejne elementy ale nic nie pomaga zawsze gdzieś coś nie pasuje. W pewnym momencie blokuje mi całkowicie edycje na każej przeglądarce (upss! fck). Lekka panika klient się wkurzy, importuje stronę na locala edytuje z palca exportuje działa (uff). Zostawiam wrzucam w IFRAMEa działające testowe logowanie i kolejny ticket do Service Desku, że niepoprawnie wyświetla formant w IE.  Po dwóch dniach znaleźli jakiś tam niedomknięty znacznik ale to nie to dalej be. Po prawie dwóch tygodniach technik , skądinąd bardzo sympatyczny gość, (cheers Matt) z rozbrajającą szczerością mówi:

"Zapomniałem, że framework jest w .NET a tam nie może być dwóch tagów FORM (jednocześnie "aktywnych"). Musisz to rozwiązać inaczej"

Zabawne, ha ha. Nie pozostało mi nic innego jak tylko napisać coś samemu. Kilka zapytań w Google’a i już wiedziałem na czym stoję. Najprościej (trzeci raz 🙂 ) było napisać w JS skrypt, który tworzył element FORM w pamięci przeglądarki, a następnie wstawiał tam elementy wpisane przez użytkownika, wszystko oczywiście transparentne dla niego. Naklikałęm coś takiego.


function open(verb, url)   {
   var form = document.createElement("form");
   form.action = url;
   form.method = verb;
   form.target = '_blank';
    var User = document.getElementById("Username1").value;
    var Pass = document.getElementById("Password1").value;

    var input1 = document.createElement("input");
       input1.name = 'Username';
       input1.value = User;
       form.appendChild(input1);

    var input2 = document.createElement("input");
       input2.name = 'Password';
       input2.value = Pass;
       form.appendChild(input2);

   form.style.display = 'none';
   document.body.appendChild(form);
   form.submit(); }

Co ten skrypt robi. Funkcja open tworzy nam element FORM z następującymi atrybutami:

  • action = ze zmienną url gdzie w wywołaniu funkcji podamy adres servera logowania,
  • method = ze zmienną verb gdzie podamy rodaj zapytania POST, można tutaj od razu wpisać POST lekko modyfikując wywołanie funkcji.
  • target = z parametrem _blank gdzie ma się otworzyć nowa strona.

Następnie tworzymy dwie zmienne User oraz Pass gdzie pobieramy dane logowania wpisane na naszej stronie w polach o ID Username1 oraz Password1. Następnie zmienną input1 tworzymy w naszym formularzu pole input z atrybutem name ustawionym na Username (atrybut ten powinien zgadzać się z nazwą parametru wysyłającego POSTem login użytkownika) oraz parametrem value gdzie podajemy wartość zmiennej User wcześniej pobraną z pola Username1 i podczepiamy do formy poprzez form.appendChild(input1).  Analogicznie tworzymy pole dla hasła używamy zmiennej input2 tworzymy w naszym formularzu pole input z atrybutem name ustawionym na Pass (atrybut ten powinien zgadzać się z nazwą parametru wysyłającego POSTem hasło użytkownika) oraz parametrem value gdzie podajemy wartość zmiennej Pass wcześniej pobraną z pola Password1 i podczepiamy do formy poprzez form.appendChild(input2). Na końcu ustawiamy aby formant był niewidoczny form.style.display = ‚none’; i do ciala naszego dokumentu dodajemy tak skonstruowany formant document.body.appendChild(form); i wysyłamy wszystkie dane  form.submit();

 

 function open(verb, url)
  {
  var form = document.createElement("form");
  form.action = url;
  form.method = verb;
  form.target = '_blank';
      var User = document.getElementById("Username1").value;
    var Pass = document.getElementById("Password1").value;
    var input1 = document.createElement("input");
      input1.name = 'Username';
      input1.value = User;
      form.appendChild(input1);
      
    var input2 = document.createElement("input");
      input2.name = 'Password';
      input2.value = Pass;
      form.appendChild(input2);

  form.style.display = 'none';
  document.body.appendChild(form);
  form.submit();
}

Oprócz tego tworzymy także funkcję która nam to wszystko ładnie wyśle podpięta pod przycisk submit wstawiony na stronie

function open_win()
{
    open('POST', 'SERVER');

}

Bardzo proste po prostu wywołujemy naszą fukcję z parametrem ‚POST’ przekazanego do zmiennej verb w wyżej opisanej funkcji open oraz parametrem ‚SERVER’ przekazywanym w zmiennej url funkcji open gdzie podajemy adres url serwera logowania z oryginalnej formatki.

Na koniec tworzymy nasz panel logowania w HTMLu pamiętając o ID pól Username1 oraz Password1 oraz wywołać funkcję wysyłającą po kliknięciu na button.

<div id="login" >
    
    <span class="label" >Username</span><br />
    <input name="Username" id="Username1" type="text" value=""><br />
    <span class="label" >Password</span><br />
    <input name="Password" id="Password1" type="Password" value=""><br />
    
<script>

    function open(verb, url)
  {
  var form = document.createElement("form");
  form.action = url;
  form.method = verb;
  form.target = '_blank';
      var User = document.getElementById("Username1").value;
    var Pass = document.getElementById("Password1").value;
    var input1 = document.createElement("input");
      input1.name = 'Username';
      input1.value = User;
      form.appendChild(input1);
      
    var input2 = document.createElement("input");
      input2.name = 'Password';
      input2.value = Pass;
      form.appendChild(input2);

  form.style.display = 'none';
  document.body.appendChild(form);
  form.submit();
}

function open_win()
{
    open('POST', 'SERVER');

}

    </script>
    <input type="button" value="Login" onclick="open_win()">
    </div>
    

Mam nadzieję, że czytelnie opisałem sposób wysłania argumentów POST przy użyciu skryptu JS.