# JSON
- JSON is JavaScript Object Notation
- Lightweight data exchange format that is easily for humans to read or write
轻量级数据交换格式,便于人类读写 - Plain text format that is language independent but was based on a subset of JavaScript language syntax
独立于语言但基于 JavaScript 语言语法子集的纯文本格式 - Usable in most languages so it is an ideal data-interchange format
可在大多数语言中使用,因此是一种理想的数据交换格式 - JSON is built on two universal data structures that map to almost all programming languages
JSON 构建在两种通用数据结构之上,这两种数据结构几乎映射到所有编程语言
- Collection of name/value pairs name/value 对的集合
- Realized in languages as object, record, struct, dictionary, hash table, keyed list, or associative array
以对象、记录、结构、字典、哈希表、键表或关联数组等语言实现- In JSON an JavaScript this is an Object
- Unordered set of name/value pairs
name/value 对的无序集合
- Realized in languages as object, record, struct, dictionary, hash table, keyed list, or associative array
- Ordered list of values 值的有序列表
- Realized in languages as array, vector, list, or sequence
以数组、向量、列表或序列等语言实现- In JSON and JavaScript this is an Array
- Ordered collection of values
值的有序集合
- Realized in languages as array, vector, list, or sequence
# Standard
Standardized by ECMA International as ECMA-404
Property names must be double quoted
属性名称必须用双引号引起来String values must be double quoted
字符串值必须用双引号引起来Trailing commas are forbidden
禁止使用尾随逗号Numbers can not have leading zeros
数字不能有前导零If a number has a decimal point, it must be followed by at least one digit
如果数字有小数点,则后面必须至少跟一个数字NaN
andInfinity
are not supported
不支持NaN
和Infinity
Values can be:
- object
- array
- string
- number
- boolean value of
true
orfalse
- null
JSON Example that could represent a person https://en.wikipedia.org/wiki/JSON
# Methods
- JavaScript provides a JSON object which contains methods for parsing JSON text to JavaScript objects and converting JavaScript objects to JSON text.
JavaScript 提供了一个 JSON 对象,其中包含将 JSON 文本解析为 JavaScript 对象并将 JavaScript 对象转换为 JSON 文本的方法。 - These methods are available on the JSON object
这些方法在 JSON 对象上可用
JSON.parse(text)
- The parse method will convert the JSON formatted text string that is passed to it to the corresponding JavaScript objects
解析方法将传递给它的 JSON 格式的文本字符串转换为相应的 JavaScript 对象 JSON.stringify(value)
- The stringify method will convert JavaScript objects to the corresponding JSON formatted text
Stringify 方法将 JavaScript 对象转换为相应的 JSON 格式文本
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON
https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/JSON
# AJAX
- AJAX – Asynchronous JavaScript And XML
异步 JavaScript 和 XML - AJAX is not a programming or markup language
AJAX 不是编程或标记语言 - AJAX is a combination of other technologies:
AJAX 是其他技术的组合:- Browser built-in object
XMLHttpRequest
to request data from a server
浏览器内置对象XMLHttpRequest
,用于从服务器请求数据 - JavaScript and HTML DOM to modify the page once data is received
接收到数据后修改页面的 JavaScript 和 HTML DOM
- Browser built-in object
- Use of XML is not required even though it is in the name. XML, JSON, text/HTML are common
即使名称中有 XML,也不需要使用它。XML、JSON、文本 / HTML 很常见 - Request is sent to server and response is received asynchronously and processed by JavaScript without a full page reload. This allows you to update parts of a web page without reloading the entire page.
请求被发送到服务器,响应被异步接收并由 JavaScript 处理,而无需重新加载整个页面。这允许您更新网页的部分内容,而无需重新加载整个页面。
# Basic Steps
- Event occurs in page that triggers AJAX request (click or something)
触发 AJAX 请求的页面中发生事件 (单击或其他) - XMLHttpRequest object is created and configured
创建并配置 XMLHttpRequest 对象 - The XMLHttpRequest object sends an asynchronous request to the server
XMLHttpRequest 对象向服务器发送异步请求 - Server processes the request in back-end code
服务器在后端代码中处理请求 - Server sends a response back to the XMLHttpRequest object including the results as response text. Check readyState and status to see if success.
服务器将响应发送回 XMLHttpRequest 对象,其中包括作为响应文本的结果。检查 ReadyState 和 Status 以查看是否成功。 - The XMLHttpRequest object uses the configured callback function to run and process the results if successful, or proper error response if not
如果成功,XMLHttpRequest 对象使用配置的回调函数运行和处理结果,如果不成功则使用适当的错误响应 - JavaScript in the callback function updates the HTML, DOM, and CSS of the page as needed
回调函数中的 javascript 根据需要更新页面的 html、 dom 和 css
# XMLHttpRequest XHR
- All modern browsers and IE 7 + support the native XMLHttpRequest object.
所有现代浏览器和 IE 7 + 都支持原生 XMLHttpRequest 对象。 - For IE < 7 support you would need to use the active x version. (not a problem anymore, if interested there are resources online that talk about this)
- Important Properties and Methods if
xhr === XMLHttpRequest
xhr.onreadystatechange
xhr.readyState
xhr.status
xhr.responseText
xhr.open();
xhr.send();
- Ready State is an unsigned int
就绪状态是无符号整型- Can use constant as comparison instead of the number.
可以使用常量作为比较,而不是数字。XMLHttpRequest.DONE
same as4
- Can use constant as comparison instead of the number.
- https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest
- https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest
# Same-Origin Policy
- Script code must come from same server, domain, subdomain, protocol, port as the ajax call
脚本代码必须来自与 ajax 调用相同的服务器、域、子域、协议和端口- http://en.wikipedia.org/wiki/Same_origin_policy
CORS
will allow for cross-origin requests- https://enable-cors.org/
- https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
- Basic CORS support can be achieved as long as the cross-origin resource providing the data sets the proper header
只要跨源资源提供了合适的数据集头,就可以实现基本的 cors 支持Access-Control-Allow-Origin: *
# Basic Example
var myRequest = new XMLHttpRequest(); | |
myRequest.onreadystatechange = function() { | |
if (myRequest.readyState === 4) { | |
if (myRequest.status === 200) { | |
var myArray = JSON.parse(myRequest.responseText); | |
parseData(myArray); | |
} | |
} | |
} | |
myRequest.open('GET', 'http://libertyville.rice.iit.edu/scripts/data.php', true); | |
myRequest.send(); | |
function parseData(arr) { | |
console.log(arr); | |
} |
var myRequest = new XMLHttpRequest(); | |
myRequest.onreadystatechange = function() { | |
if (myRequest.readyState === XMLHttpRequest.DONE) { | |
if (myRequest.status === 200) { | |
var myArray = JSON.parse(myRequest.responseText); | |
parseData(myArray); | |
} | |
} | |
}; | |
myRequest.open('GET', 'http://libertyville.rice.iit.edu/scripts/data.php', true); | |
myRequest.send(); | |
function parseData(arr) { | |
console.log(arr); | |
} |
var myRequest = new XMLHttpRequest(); | |
myRequest.onreadystatechange = function(){ | |
if (myRequest.readyState === 4 && myRequest.status === 200) { | |
var myArray = JSON.parse(myRequest.responseText); | |
parseData(myArray); | |
} | |
}; | |
myRequest.open('GET', 'http://libertyville.rice.iit.edu/scripts/data.php', true); | |
myRequest.send(); | |
function parseData(arr) { | |
console.log(arr); | |
} |
# AJAX Events and Monitoring
- The XMLHttpRequest object allows us to listen for events that occur when the request is being processed, including progress, errors, and more.
XMLHttpRequest 对象允许我们监听处理请求时发生的事件,包括进度、错误等等。 - Must
add
before callingopen()
- Doesn't work on
file://
protocol - Events:
progress
load
error
abort
loadend
– happens at the end of all three (load, error, abort) events. Can not tell which event happened though. Useful for things that need to happen no matter which event happens.
发生在所有三个 (加载、错误、中止) 事件的结尾。不知道发生了什么事。不管发生什么事情,对于需要发生的事情来说都是有用的。
- An event object is the parameter of the event handler function
事件对象是事件处理函数的参数 - See section on monitoring progress https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest
# AJAX Example using event for load
var myRequest = new XMLHttpRequest(); | |
myRequest.addEventListener('load', parseData); | |
myRequest.open('GET', 'http://libertyville.rice.iit.edu/scripts/data.php', true); | |
myRequest.send(); | |
function parseData(evt) { | |
console.log(evt); | |
var myArray = JSON.parse(evt.target.responseText); | |
// code to process the array and modify the DOM | |
} |
# Fetch API
- Fetch API is a promise based api for doing AJAX requests.
- No support in IE but other modern browsers do support
- https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API
- https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
- https://developers.google.com/web/updates/2015/03/introduction-to-fetch
fetch('http://libertyville.rice.iit.edu/scripts/data.php') | |
.then(function(response) { | |
return response.json(); | |
}) | |
.then(function(myJson){ | |
console.log(JSON.stringify(myJson)); | |
}); |
# AJAX Libraries
There is Ajax support built-in to most JavaScript libraries including jQuery
包括 jquery 在内的大多数 javascript 库都内置了 ajax 支持jQuery ajax support is based on
$.ajax();
functionSee jQuery docs for api reference
Using libraries can simplify your use of Ajax
使用库可以简化 ajax 的使用New native fetch api is a more modern way to do ajax
Popular AJAX library is
Axios
- Promise based HTTP client for the browser and node.js
- https://www.npmjs.com/package/axios
# AJAX POST & Data
# POST
- Send data to a server typically with a
POST
request
通常以发送请求的方式将数据发送到服务器 - Datatype of the Body of the request is indicated by the
Content-Type
header
请求主体的数据类型由Content-Type
标头指示 - HTML Forms typically submit using a
POST
request
HTML 表单通常使用 post 请求提交- When sending by form the form tags
enctype
attribute will determine the content type
当通过表单发送时,表单标记enctype
属性将决定内容类型 application/x-www-form-urlencoded
- Keys and values have an
=
between them - Key-value pairs are separated with an
&
- Non-alpha characters are percent encoded so not usable for binary data
非字母字符采用百分比编码,因此不适用于二进制数据
- Keys and values have an
multipart/form-data
- Each value is sent as a block of data in the body with a delimiter between them
每个值都以数据块的形式在主体中发送,数据块之间有分隔符 - Use when binary data needs to be sent
当需要发送二进制数据时使用
- Each value is sent as a block of data in the body with a delimiter between them
text/plain
- When sending by form the form tags
- If using AJAX to send a request the body can be of any data type you want
application/json
is one example for JSON data
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST
# POST with XMLHttpRequest
- You can use the
XMLHttpRequest
object'ssetRequestHeader()
method to set headers on the request.- This is how you would set the
Content-Type
header to let the server know what the data type of the request body is.
- This is how you would set the
- The
XMLHttpRequest
object'ssend()
method can take one parameter.- That parameter is the body of the request
- https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/send
# POST with Fetch
- Fetch defaults to a
GET
request so to send aPOST
request you need to use the optionalinit
parameter to thefetch()
method.
Fetch 默认为GET
请求,所以要发送POST
请求,你需要给fetch()
方法使用可选的init
参数。 - The
init
object is the second parameter to thefetch()
method and it is an objectinit
对象是fetch()
方法的第二个参数,它是一个对象 - In that object you can set the body, headers, and request method, among other things
在该对象中,您可以设置 body、header 和 request 方法等 - Headers are set by creating a new Headers object and appending headers to it before setting it to the headers key in the
init
object.
头信息的设置是通过创建一个新的 Headers 对象,并在将其设置为 init 对象中的 Headers 键之前附加头信息。 - The body key can be a list of data types but is typically a string of JSON or formurlencoded data
body 键可以是一个数据类型列表,但通常是一个 JSON 字符串或 forurlencoded 数据 - https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch
# DEMO
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>AJAX Basic</title> | |
</head> | |
<body> | |
<button id="btn">Click Me!</button> | |
<div id="results"></div> | |
<script> | |
document.getElementById('btn').addEventListener('click', function(){ | |
console.log('Button Clicked!'); | |
let myRequest = new XMLHttpRequest(); | |
myRequest.onreadystatechange = function(){ | |
if (myRequest.readyState === 4 && myRequest.status === 200) { | |
console.log(myRequest.responseText); | |
console.log(JSON.parse(myRequest.responseText)); | |
let a = JSON.parse(myRequest.responseText); | |
let table = document.createElement('table'); | |
for(let i = 0; i < a.length; i++) { | |
console.log(a[i]); | |
let row = document.createElement('tr'); | |
row.id = a[i].id; | |
let cellproduct = document.createElement('td'); | |
let protext = document.createTextNode(a[i].title); | |
cellproduct.appendChild(protext); | |
row.appendChild(cellproduct); | |
let cellpr = document.createElement('td'); | |
let prtext = document.createTextNode(a[i].completed); | |
cellpr.appendChild(prtext); | |
row.appendChild(cellpr); | |
table.appendChild(row); | |
} | |
document.getElementById('results').appendChild(table); | |
} | |
}; | |
myRequest.open('GET', 'http://jsonplaceholder.typicode.com/todos'); | |
myRequest.send(); | |
}); //end button click event handler | |
</script> | |
</body> | |
</html> |
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>AJAX with Events</title> | |
</head> | |
<body> | |
<button id="btn">Click Me!</button> | |
<div id="results"></div> | |
<script> | |
document.getElementById('btn').addEventListener('click', function(){ | |
console.log('Button Clicked!'); | |
let myRequest = new XMLHttpRequest(); | |
myRequest.addEventListener('load', function(evt){ | |
console.log(evt); | |
let a = JSON.parse(evt.target.responseText); | |
let table = document.createElement('table'); | |
for(let i = 0; i < a.length; i++) { | |
console.log(a[i]); | |
let row = document.createElement('tr'); | |
row.id = a[i].id; | |
let cellproduct = document.createElement('td'); | |
let protext = document.createTextNode(a[i].title); | |
cellproduct.appendChild(protext); | |
row.appendChild(cellproduct); | |
let cellpr = document.createElement('td'); | |
let prtext = document.createTextNode(a[i].completed); | |
cellpr.appendChild(prtext); | |
row.appendChild(cellpr); | |
table.appendChild(row); | |
} | |
document.getElementById('results').appendChild(table); | |
}); | |
myRequest.open('GET', 'http://jsonplaceholder.typicode.com/todos', true); | |
myRequest.send(); | |
}, false); //end button click event handler | |
</script> | |
</body> | |
</html> |
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>AJAX with Fetch</title> | |
</head> | |
<body> | |
<button id="btn">Click Me!</button> | |
<div id="results"></div> | |
<script> | |
document.getElementById('btn').addEventListener('click', function(){ | |
console.log('Button Clicked!'); | |
fetch('http://jsonplaceholder.typicode.com/todos') | |
.then(function(response){ | |
return response.json(); | |
}) | |
.then(function(myJson){ | |
console.log(myJson); | |
let table = document.createElement('table'); | |
for(let i = 0; i < myJson.length; i++) { | |
console.log(myJson[i]); | |
let row = document.createElement('tr'); | |
let cellproduct = document.createElement('td'); | |
let protext = document.createTextNode(myJson[i].title); | |
cellproduct.appendChild(protext); | |
row.appendChild(cellproduct); | |
let cellpr = document.createElement('td'); | |
let prtext = document.createTextNode(myJson[i].completed); | |
cellpr.appendChild(prtext); | |
row.appendChild(cellpr); | |
table.appendChild(row); | |
} | |
document.getElementById('results').appendChild(table); | |
}); | |
}, false); //end button click event handler | |
</script> | |
</body> | |
</html> |
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<meta http-equiv="X-UA-Compatible" content="ie=edge"> | |
<title>Document</title> | |
</head> | |
<body> | |
<div id="formcontrols"> | |
<label>Name: <input type="text" name="name_in" id="name_in"></label><br> | |
<label>Email: <input type="text" name="email_in" id="email_in"></label><br> | |
<button id="btn-submit">POST with Fetch using JSON</button> | |
<button id="btn-submit2">POST with Fetch using form url encoded</button> | |
<button id="btn-submit3">POST with standard AJAX using JSON</button> | |
<button id="btn-submit4">POST with standard AJAX using form url encoded</button> | |
</div> | |
<div id="requestdata"> | |
</div> | |
<div id="results"> | |
</div> | |
<script> | |
document.addEventListener('DOMContentLoaded', function(){ | |
document.getElementById('btn-submit').addEventListener('click', function(){ | |
let nameval = document.getElementById('name_in').value.trim(); | |
let emailval = document.getElementById('email_in').value.trim(); | |
let body = {name: nameval, email: emailval}; | |
let headers = new Headers(); | |
headers.append('Content-Type', 'application/json'); | |
fetch('postback.php', { | |
method: 'post', | |
body: JSON.stringify(body), | |
headers: headers | |
}).then(function(res){ | |
return res.json(); | |
}).then(function(data){ | |
console.log(data); | |
printRequestDataToPage(JSON.stringify(body)); | |
printToPage(data); | |
}); | |
}); | |
document.getElementById('btn-submit2').addEventListener('click', function(){ | |
let nameval = document.getElementById('name_in').value.trim(); | |
let emailval = document.getElementById('email_in').value.trim(); | |
let body = `name=${nameval}&email=${emailval}`; | |
let headers = new Headers(); | |
headers.append('Content-Type', 'application/x-www-form-urlencoded'); | |
fetch('postback.php', { | |
method: 'post', | |
body: body, | |
headers: headers | |
}).then(function(res){ | |
return res.json(); | |
}).then(function(data){ | |
console.log(data); | |
printRequestDataToPage(body); | |
printToPage(data); | |
}); | |
}); | |
document.getElementById('btn-submit3').addEventListener('click', function(){ | |
let nameval = document.getElementById('name_in').value.trim(); | |
let emailval = document.getElementById('email_in').value.trim(); | |
let body = {name: nameval, email: emailval}; | |
let xhr = new XMLHttpRequest(); | |
xhr.open('POST', 'postback.php', true); | |
xhr.setRequestHeader('Content-Type', 'application/json'); | |
xhr.onreadystatechange = function(evt){ | |
if (this.readyState === XMLHttpRequest.DONE && this.status === 200) { | |
console.log(JSON.parse(this.responseText)); | |
printRequestDataToPage(JSON.stringify(body)); | |
printToPage(JSON.parse(this.responseText)); | |
} | |
}; | |
xhr.send(JSON.stringify(body)); | |
}); | |
document.getElementById('btn-submit4').addEventListener('click', function(){ | |
let nameval = document.getElementById('name_in').value.trim(); | |
let emailval = document.getElementById('email_in').value.trim(); | |
let body = `name=${nameval}&email=${emailval}`; | |
let xhr = new XMLHttpRequest(); | |
xhr.open('POST', 'postback.php', true); | |
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); | |
xhr.onreadystatechange = function(evt){ | |
if (this.readyState === XMLHttpRequest.DONE && this.status === 200) { | |
console.log(JSON.parse(this.responseText)); | |
printRequestDataToPage(body); | |
printToPage(JSON.parse(this.responseText)); | |
} | |
}; | |
xhr.send(body); | |
}); | |
function printToPage(JSONdata){ | |
let resultsDiv = document.getElementById('results'); | |
resultsDiv.innerHTML = ''; | |
let head1 = document.createElement('h3'); | |
head1.appendChild(document.createTextNode('JSON Response Data')); | |
resultsDiv.appendChild(head1); | |
let code = document.createElement('pre'); | |
code.style.marginTop = '20px'; | |
code.appendChild(document.createTextNode(JSON.stringify(JSONdata, undefined, 2))); | |
resultsDiv.appendChild(code); | |
let head2 = document.createElement('h3'); | |
head2.appendChild(document.createTextNode('Formatted Response Data')); | |
resultsDiv.appendChild(head2); | |
let values = document.createElement('div'); | |
values.style.marginTop = '20px'; | |
let codeTxt = `<b>name:</b> ${JSONdata.post_data.name}<br><b>email:</b> ${JSONdata.post_data.email}<br><b>method:</b> ${JSONdata.http_method}<br><b>Request Content Type:</b> ${JSONdata.request_content_type}<br><b>Timestamp:</b> ${JSONdata.time}<br>`; | |
values.innerHTML = codeTxt; | |
resultsDiv.appendChild(values); | |
} | |
function printRequestDataToPage(data) { | |
let requestDiv = document.getElementById('requestdata'); | |
requestDiv.innerHTML = ''; | |
let head1 = document.createElement('h3'); | |
head1.appendChild(document.createTextNode('Request Data')); | |
requestDiv.appendChild(head1); | |
let code = document.createElement('pre'); | |
code.style.marginTop = '20px'; | |
code.appendChild(document.createTextNode(data)); | |
requestDiv.appendChild(code); | |
} | |
});//end DOMContentLoaded | |
</script> | |
</body> | |
</html> |
<?php | |
if ( isset($_SERVER['CONTENT_TYPE']) && strtolower($_SERVER['CONTENT_TYPE']) == 'application/json' ) { | |
$inputJSON = file_get_contents('php://input'); | |
$data = json_decode($inputJSON); | |
$output = [ "post_data" => $data ]; | |
$output["time"] = date("Y-m-d H:i:s"); | |
$output["request_content_type"] = $_SERVER['CONTENT_TYPE']; | |
$output["http_method"] = $_SERVER['REQUEST_METHOD']; | |
header("Access-Control-Allow-Origin: *"); | |
header("Content-Type: application/json"); | |
echo json_encode($output); | |
} else { | |
$output = ["post_data" => $_POST]; | |
$output["time"] = date("Y-m-d H:i:s"); | |
$output["request_content_type"] = $_SERVER['CONTENT_TYPE']; | |
$output["http_method"] = $_SERVER['REQUEST_METHOD']; | |
header("Access-Control-Allow-Origin: *"); | |
header("Content-Type: application/json"); | |
echo json_encode($output); | |
} |