node之HTTP 從服務端感受ajax和form

渣渣的生存之道發表於2018-07-10

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表單格式會用分隔符將內容分離開

node之HTTP  從服務端感受ajax和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形似

node之HTTP  從服務端感受ajax和form
node之HTTP  從服務端感受ajax和form

我們隊上述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);
    })
}
複製程式碼

相關文章