ajax傳送請求,需要傳輸資料,資料有不同的型別,所以也是靠請求頭告訴後臺處理邏輯
傳輸資料的方式有很多種
http: 1.0,1.1(keep-alive) 複用連線, 2.0 https 新特點雙向通訊,多路複用
資料互動的方式
客戶端主動傳送請求給服務端,服務端返回資料,我們叫單向通訊
- 表單 (會頁面跳轉,如果是get會加個?,如果是post就會跳轉業面,頁面重新渲染,重新請求伺服器,獲取頁面,這樣就會浪費很多流量,對伺服器壓力很大) 但是一般提交我們用表單 支援跨域
- ajax 同步體驗不好,可以無重新整理頁面 1.0,2.0 ajax基於表單請求http發過去的,只是傳送方式不一樣 不支援跨域
- jsop xss攻擊,逐漸介面暴露出去,大家都可以訪問,大多數網站在廢棄中, 逐漸被cors代替
- cors 跨域資源共享,不需要前臺,直接更改服務端配置
- nginx 反向代理
- webpack proxy 反向代理
雙向通訊 連線以後,不需要客戶端主動傳送請求,服務端可以主動告訴他,會實時吧最新的資訊提交給客戶端,之前我們的做法是setInterval,但是這就有個問題,假設我們10分鐘內沒有更新呢,而用websokct當服務端變了之後會主動推送給客戶端,我們經常應用例如聊天室
- websocket (基於tcp)
我們通過node實現服務端,接收前端請求
表單 (會頁面跳轉,如果是get會加個?,如果是post就會跳轉業面,頁面重新渲染,重新請求伺服器,獲取頁面,這樣就會浪費很多流量,對伺服器壓力很大) 但是一般提交我們用表單
get | post |
---|---|
放到url裡,有限制 | 不限制大小 |
get的url形式方便分享 post通過請求體
<!-- form支援什麼格式提交get post 不識別預設get -->
<form action="http://localhost:3000/form" method="get">
使用者名稱 <input type="text" name="username"><br>
密碼 <input type="text" name="password"><br>
<input type="submit">
</form>
複製程式碼
跳轉之後的連結會有http://127.0.0.1:5500/?username=123&password=321form預設支援跨域
//服務端
let http = require('http');
let url = require('url');
let server = http.createServer(function(req,res){
let {pathname,query} = url.parse(req.url,true);
if(pathname === '/form'){
res.end(JSON.stringify(query))
}
})
server.listen(3000)
複製程式碼
把方法改成post
let http = require('http');
let url = require('url');
let querystring = require('querystring');
// let str = "username==123&&password==321";
// // 指定欄位之間的分隔符 和 key、value之間的分隔符-》物件
// let obj = querystring.parse(str,'&&','==');
// console.log(obj);
let server = http.createServer(function(req,res){
let {pathname,query} = url.parse(req.url,true);
let method = req.method.toLowerCase();//在node中取得的方法名永遠是大寫的
if(pathname === '/form'){
if(method === 'get'){
res.end(JSON.stringify(query))
}else{
let buffers = [];
//接收請求體
req.on('data',function(data){
buffers.push(data);
})
req.on('end',function(){
//表單格式接受的都是a=b&c=d
//headers[ 'content-type': 'application/x-www-form-urlencoded']
let str = Buffer.concat(buffers).toString();
res.end(JSON.stringify(querystring.parse(str)));
})
}
}
})
server.listen(3000)
複製程式碼
表單提交的檔案比較特殊
<!-- form支援什麼格式提交get post 不識別預設get enctype="multipart/form-data" 多文字,內容型別:多段form表單格式 -->
<form action="http://localhost:3000/form" method="get">
使用者名稱 <input type="text" name="username"><br>
密碼 <input type="text" name="password"><br>
<input type="submit">
</form>
複製程式碼
多段form表單格式會用分隔符將內容分離開
我們需要將內容解析,或者需要安裝npm install formidable
let http = require('http');
let url = require('url');
let querystring = require('querystring');
let formidable = require('formidable')
let path = require('path')
// let str = "username==123&&password==321";
// // 指定欄位之間的分隔符 和 key、value之間的分隔符-》物件
// let obj = querystring.parse(str,'&&','==');
// console.log(obj);
let server = http.createServer(function(req,res){
let {pathname,query} = url.parse(req.url,true);
let method = req.method.toLowerCase();//在node中取得的方法名永遠是大寫的
if(pathname === '/form'){
if(method === 'get'){
res.end(JSON.stringify(query))
}else{
var form = new formidable.IncomingForm();
//fields a=b&c=d文字 files檔案
form.keepExtensions = true;//保留字尾
form.encoding = 'utf-8';
form.uploadDir = path.join(__dirname,'./myDir');
form.parse(req, function(err, fields, files) {
});
form.on('end', function() {
res.end('上傳成功');
});
}
}
})
server.listen(3000)
複製程式碼
ajax 同步體驗不好,可以無重新整理頁面 1.0,2.0 ajax基於表單請求http發過去的,只是傳送方式不一樣
<!-- 不支援跨域,協議,主機名,埠號 表單的好處可以加自己的校驗-->
<form onsubmit="login(event)" id="form">
使用者名稱:
<input type="text" name="username" required>
<br> 密碼:
<input type="text" name="password">
<br>
<input type="submit" value="提交">
</form>
複製程式碼
function login(e) {
let $ = document.querySelector.bind(document);
function serialized(ele) {
let arr = [];
let elements = ele.elements;
for (let i = 0; i < elements.length; i++) {
let { type, name, value } = elements[i];
switch (type) {
case 'text':
case 'password':
arr.push(`${name}=${value}`);
break
default:
}
}
return arr.join('&');
}
function login(e) {
//阻止預設行為
e.preventDefault();
//表單序列化 username=123&password=456
let qs = serialized($('#form'));
//ajax4步
let xhr = new XMLHttpRequest();
xhr.open('GET', `/2.html?${qs}`, true); // true代表是否非同步
xhr.responseType = 'json';// 服務返回的應該是一個物件
xhr.timeout = 3000; // 3000過去了還沒有資料返回就是超時
xhr.ontimeout = function () {
console.log('超時')
}
xhr.onerror = function (err) {//斷網
console.log(err);
}
xhr.setRequestHeader('Content-Type', 'application/www-x-form-urlencoded');
// xhr.setRequestHeader('Content-Type','application/json')
//readyState 0 表示還沒有open 1代表open了 2 代表傳送求求 3.接收到了部分請求
xhr.onreadystatechange = function () {
console.log(xhr.readyState);
console.log(xhr.status)
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) {
console.log(xhr.response);
}
}
}
xhr.send(qs);
}
複製程式碼
需要啟動服務否則跨域
//服務程式碼
let http = require('http');
let url = require('url');
let fs = require('fs');
let path = require('path');
let querystring = require('querystring');
let server = http.createServer(function (req,res) {
let {pathname,query} = url.parse(req.url,true);
if(pathname === '/2.html'){
let method = req.method.toLowerCase();
if(method === 'get'){ //get方法
res.end(JSON.stringify(query));
}else{//post方法
let buffers = [];
req.on('data', function (data) {
buffers.push(data);
});
req.on('end', function () {
let str = Buffer.concat(buffers).toString();
console.log(str);
res.end(JSON.stringify(querystring.parse(str)));
})
}
return
}
if(pathname === '/'){
return fs.createReadStream(path.join(__dirname,'./1.html')).pipe(res);
}
let p = path.join(__dirname, pathname);
fs.stat(p,function (err,stat) {
if(!err){
fs.createReadStream(p).pipe(res);
}else{
res.statusCode = 404;
res.end(`NotFound`);
}
})
});
server.listen(3000);
複製程式碼
post請求和get形似
我們隊上述ajax做個簡單的封裝
function login(e) {
//阻止預設行為
e.preventDefault();
//表單序列化 username=123&password=456
let qs = serialized($('#form'));
//ajax4步
let xhr = new XMLHttpRequest();
ajax({
url: '/2.html',
method: 'post',
dataType: 'json',
contentType:'application/www-x-form-urlencoded',//只有post需要傳
data: qs
}).then(data=>{
console.log(data);
}).catch(e=>{
console.log(e);
});
}
function ajax(options) {
return new Promise((resolve,reject)=>{
let {
url = new Error('url must a string'),
method = "get",
dataType = "text",
data = null,
success,
contentType,
error
} = options;
let xhr = new XMLHttpRequest();
if (method == 'get') {
xhr.open(method, `${url}?${data}`, true);//如果是get請求,要將資料拼接到url
} else {
xhr.open(method, url, true);
xhr.setRequestHeader('ContentType', contentType);//設定請求頭
}
xhr.responseType = dataType;//響應型別
xhr.onerror = function (err) {
error && error(err);
reject(err)
}
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) {
console.log(xhr.response)
success && success(xhr.response);
resolve(xhr.response)
}
}
}
data = method === 'get' ? null : data;
xhr.send(data);
})
}
複製程式碼