آشنایی با JSONP و ایجاد HTML در JSON

09 خرداد 1398
Advanced-Javascript-jsonp

JSON و HTML

از قسمت های قبلی این دوره یاد گرفته ایم که JSON می تواند به راحتی تبدیل به جاوا اسکریپت شود و از طرفی جاوا اسکریپت نیز می تواند کد های HTML تولید کند بنابراین می توان گفت که JSON به نوعی HTML تولید می کند. به طور مثال ما جدول HTML زیر را با استفاده از اطلاعات دریافتی توسط JSON ساخته ایم:

<!DOCTYPE html>
<html>
<body>

<h2>Make a table based on JSON data.</h2>

<p id="demo"></p>

<script>
var obj, dbParam, xmlhttp, myObj, x, txt = "";
obj = { table: "customers", limit: 20 };
dbParam = JSON.stringify(obj);
xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
  if (this.readyState == 4 && this.status == 200) {
    myObj = JSON.parse(this.responseText);
    txt += "<table border='1'>"
    for (x in myObj) {
      txt += "<tr><td>" + myObj[x].name + "</td></tr>";
    }
    txt += "</table>"    
    document.getElementById("demo").innerHTML = txt;
  }
};
xmlhttp.open("POST", "json_demo_db_post.php", true);
xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xmlhttp.send("x=" + dbParam);
</script>

</body>
</html>

مشاهده ی خروجی

ما می توانیم این اطلاعات را در یک منوی drop down نیز قرار دهیم و لزومی به استفاده از جدول ها نداریم:

<!DOCTYPE html>
<html>
<body>

<h2>Make a table based on the value of a drop down menu.</h2>

<select id="myselect" onchange="change_myselect(this.value)">
  <option value="">Choose an option:</option>
  <option value="customers">Customers</option>
  <option value="products">Products</option>
  <option value="suppliers">Suppliers</option>
</select>

<p id="demo"></p>

<script>
function change_myselect(sel) {
  var obj, dbParam, xmlhttp, myObj, x, txt = "";
  obj = { table: sel, limit: 20 };
  dbParam = JSON.stringify(obj);
  xmlhttp = new XMLHttpRequest();
  xmlhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      myObj = JSON.parse(this.responseText);
      txt += "<table border='1'>"
      for (x in myObj) {
        txt += "<tr><td>" + myObj[x].name + "</td></tr>";
      }
      txt += "</table>"    
      document.getElementById("demo").innerHTML = txt;
      }
    };
  xmlhttp.open("POST", "json_demo_db_post.php", true);
  xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
  xmlhttp.send("x=" + dbParam);
}
</script>

</body>
</html>

مشاهده ی خروجی

حتی می توانیم آن را در قالب یک لیست drop down نیز دربیاوریم:

<!DOCTYPE html>
<html>
<body>

<h2>Make a drop down list based on JSON data.</h2>

<p id="demo"></p>

<script>
var obj, dbParam, xmlhttp, myObj, x, txt = "";
obj = { table: "customers", limit: 20 };
dbParam = JSON.stringify(obj);
xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
  if (this.readyState == 4 && this.status == 200) {
    myObj = JSON.parse(this.responseText);
    txt += "<select>"
    for (x in myObj) {
      txt += "<option>" + myObj[x].name;
    }
    txt += "</select>"
    document.getElementById("demo").innerHTML = txt;
  }
};
xmlhttp.open("POST", "json_demo_db_post.php", true);
xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xmlhttp.send("x=" + dbParam);
</script>

</body>
</html>

مشاهده ی خروجی

JSONP چیست؟

JSONP (مخفف JSON with Padding - به معنی JSON به همراه padding) متدی برای ارسال داده های JSON است که مشکلات بین-دامنه ای را حل می کند. JSONP از شیء XMLHttpRequest استفاده نمی کند بلکه به جای آن از <script> استفاده می کند.

همانطور که می دانید درخواست فایل از یک دامنه ی دیگر مشکلاتی را ایجاد می کند چرا که خلاف خط مشیء و قوانین مربوطه است (به دلیل مسائل امنیتی) اما درخواست یک script از یک دامنه ی دیگر چنین محدودیت هایی را ندارد بنابراین می توانیم به جای آنکه از شیء XMLHttpRequest استفاده کنیم، فایل خود را از طریق تگ script انجام دهیم:

<script src="demo_jsonp.php">

به طور مثال در کد زیر، سرور نتیجه را در فراخوانی تابع جمع می کند:

<?php

$myJSON = '{"name":"John", "age":30, "city":"New York"}';

echo "myFunc(".$myJSON.");";

?>

خروجی این کد عبارت زیر است:

myFunc({"name":"John", "age":30, "city":"New York"});

در واقع نتیجه تابعی به نام myFunc را صدا می زند و JSON را به عنوان پارامتر به آن می دهد. البته باید مطمئن باشید که چنین تابعی برای سمت کلاینت وجود داشته باشد. در مثال ما این تابع در سمت کلاینت وجود داشت و آماده ی دریافت و مدیریت JSON بود:

<!DOCTYPE html>
<html>

<body>

<h2>Request JSON using the script tag</h2>
<p>The PHP file returns a call to a function that will handle the JSON data.</p>

<p id="demo"></p>

<script>
function myFunc(myObj) {
  document.getElementById("demo").innerHTML = myObj.name;
}
</script>

<script src="demo_jsonp.php"></script>

</body>
</html>

مشاهده ی خروجی

همانطور که حدس میزدید در خروجی عبارت "John" برای ما به نمایش در می آید.

مثال بالا تابع myFunc را زمانی اجرا می کند که صفحه در حال بارگذاری است و به مکان قرار دادن تگ script در صفحه تان بستگی دارد. این شیوه اصلا شیوه ی خوبی نیست و بهتر ما آن را پویا تر کنیم؛ یعنی تگ script زمانی به وجود بیاید که به آن نیاز داشته باشیم:

<!DOCTYPE html>
<html>

<body>

<h2>Click the Button.</h2>
<p>A script tag with a src attribute is created and placed in the document.</p>
<p>The PHP file returns a call to a function with the JSON object as a parameter.</p>

<button onclick="clickButton()">Click me!</button>

<p id="demo"></p>

<script>
function clickButton() {
  var s = document.createElement("script");
  s.src = "demo_jsonp.php";
  document.body.appendChild(s);
}

function myFunc(myObj) {
  document.getElementById("demo").innerHTML = myObj.name;
}
</script>

</body>
</html>

مشاهده ی خروجی

این تابع زمانی که کسی روی دکمه کلیک کند یک تگ Script ساخته و آن را در سند ما قرار می دهد. اما این مثال هنوز هم به طور کامل پویا نیست. برای پویایی بیشتر می توانیم JSON را به فایل PHP بفرستیم تا فایل PHP بر اساس اطلاعاتی که دریافت می کند یک شیء JSON را برگرداند:

<?php
header("Content-Type: application/json; charset=UTF-8");
$obj = json_decode($_GET["x"], false);

$conn = new mysqli("myServer", "myUser", "myPassword", "Northwind");
$result = $conn->query("SELECT name FROM ".$obj->$table." LIMIT ".$obj->$limit);
$outp = array();
$outp = $result->fetch_all(MYSQLI_ASSOC);

echo "myFunc(".json_encode($outp).")";
?>

در این مثال ابتدا درخواست را با استفاده از تابع ()json_decode به یک شیء تبدیل می کنیم:

$obj = json_decode($_GET["x"], false);

سپس به پایگاه داده متصل می شویم:

$conn = new mysqli("myServer", "myUser", "myPassword", "Northwind");

و اطلاعات درخواستی را درون یک آرایه می ریزیم و آن آرایه را به یک شیء اضافه می کنیم:

$result = $conn->query("SELECT name FROM ".$obj->$table." LIMIT ".$obj->$limit);
$outp = array();
$outp = $result->fetch_all(MYSQLI_ASSOC);

حالا آرایه را با استفاده از ()json_encode به JSON تبدیل میکنیم و myFunc را به شیء برگردانده شده اضافه می کنیم:

echo "myFunc(".json_encode($outp).")";

سپس می توانیم myFunc را از فایل PHP صدا بزنیم:

<!DOCTYPE html>
<html>

<body>

<h2>Click the Button.</h2>
<p>A script tag with a src attribute is created and placed in the document.</p>
<p>The PHP file returns a call to a function with the JSON object as a parameter.</p>

<button onclick="clickButton()">Click me!</button>

<p id="demo"></p>

<p>Try changing the table property from "customers" to "products".</p>

<script>
function clickButton() {
  var obj, s
  obj = { table: "customers", limit: 10 };
  s = document.createElement("script");
  s.src = "jsonp_demo_db.php?x=" + JSON.stringify(obj);
  document.body.appendChild(s);
}

function myFunc(myObj) {
  var x, txt = "";
  for (x in myObj) {
    txt += myObj[x].name + "<br>";
  }
  document.getElementById("demo").innerHTML = txt;
}
</script>

</body>
</html>

مشاهده ی خروجی

سوال: زمانی که به فایل سمت سرور دسترسی نداریم چطور به سرور بگوییم که تابع صحیح را صدا بزند؟

پاسخ: برخی اوقات فایل سمت سرور یک تابع از نوع callback را به عنوان یک پارامتر به شما می دهد. ما می توانیم از همین پارامتر استفاده کنیم:

<!DOCTYPE html>
<html>

<body>

<h2>Request With a Callback Function</h2>
<p>The PHP file returns a call to the function you send as a callback.</p>

<button onclick="clickButton()">Click me!</button>

<p id="demo"></p>

<script>
function clickButton() {
  var s = document.createElement("script");
  s.src = "demo_jsonp2.php?callback=myDisplayFunction";
  document.body.appendChild(s);
}

function myDisplayFunction(myObj) {
  document.getElementById("demo").innerHTML = myObj.name;
}
</script>

</body>
</html>

مشاهده ی خروجی

قسمت مهم این کد اینجاست:

 s.src = "jsonp_demo_db.php?callback=myDisplayFunction";

امیدوارم این قسمت برای شما مفید بوده باشد.

تمام فصل‌های سری ترتیبی که روکسو برای مطالعه‌ی دروس سری جاوا اسکریپت پیشرفته توصیه می‌کند:
نویسنده شوید
دیدگاه‌های شما

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.