nodejs入门API之http模块

  • HTTP上的一些API及应用
  • HTTP模块上的服务(server)与响应(response)
  • HTTP模块上的消息(message)
  • HTTP模块上的代理(agent)与请求(request)
  • get请求与post请求的差异与示例
  • 登入跳转问题(重定向)

 一、HTTP上的一些API及应用

  • http.Agent:http请求代理,用来管理客户端连接的持久性和重用。
  • http.ClientRequest:由http.request()产生,用来管理已被放入请求队列中的请求,比如可以通过setHeader(name, value)向请求头添加请求头。
  • http.Server:该类继承net.server,用来管理来自客户端的http请求。
  • http.ServerResponse:此类型的对象由 HTTP 服务器在内部创建,而不是由用户创建,用来管理服务端接收到http请求后响应客户端的相关内容。 它作为第二个参数传给 'request' 事件。
  • http.IncomingMessage:此类型的对象由 http.Server 或 http.ClientRequest 创建,并分别作为第一个参数传给 'request' 和 'response' 事件,用来表示接收到的http请求的模型。 它可用于访问响应状态、消息头、以及数据。
  • http.METHODS:该属性用来获取当前node环境下支持的http请求方法,比如:[GET, POST,...]
  • http.STATUS_CODES:该属性用来获取http的响应码及说明,比如:{'100': 'Continue','200': 'OK','404': 'Not Found','500': 'Internal Server Error',...}
  • http.createServer([options][,requestListener]):用来实例化一个http.server对象。参数:options可选,有两个属性IncomingMessage、ServerResponse,分别用来指定要使用的 IncomingMessage 类和 ServerResponse 类,用来扩该类的初始属性,默认使用原始的类型;requestListener可选,该参数是一个方法,会被自动添加到‘request’事件作为回调函数。
  • http.get(options[,callback]):用来发送GTE方法的HTTP请求
  • http.get(url[, options][, callback]):同上。
  • http.globalAgent:Agent 的全局实例,作为所有 HTTP 客户端请求的默认值。
  • http.maxHeaderSize:只读属性,指定 HTTP 消息头的最大允许大小(以字节为单位)。 默认为 8KB。 可使用 --max-http-header-size 命令行选项进行配置。
  • http.request(options[,callback]):用来发起http请求。
  • http.request(url[,options][,callback]):同上。

 二、HTTP模块上的服务(server)与响应(response)

http.Server类

http.server事件

  • checkContinue 事件:每次收到 HTTP Expect: 100-continue 的请求时都会触发。处理此事件时,如果客户端继续发送请求主体就会默认调用response.writeContinue(),即向客户端响应HTTP/1.1 100 Continue 消息,表示应发送请求主体。
  • checkExpectation 事件:每次收到带有 HTTP Expect 请求头的请求时触发,其中值不是 100-continue。 如果未监听此事件,则服务器将根据需要自动响应 417 Expectation Failed。(及客户端期望某个操作,但不是100-continue向服务发送报文主体,这时候就需要该事件进行处理,如果没有设置该事件的处理方法,则自动响应客户端417表示服务端无法满足该期望)
  • clientError 事件:如果客户端连接触发error事件,服务端连接则会在此处转发,此事件监听器负责关闭或销毁底层套字节,比如直接在监听事件中调用socket.end("HTTP/1.1 400 Bad Request\r\n\r\n");实现优雅的关闭连接,而不是突然切断连接(切断连接后tcp协议还会有一系列的底层动作,采用这种方式关闭可以避免不必要的消耗)。并且可以在此监听事件中实现对客户端错误进行日志记录,有利于错误筛查与修复。
  • close 事件:当服务关闭时触发。
  • connect 事件:客户端请求连接时触发该监听事件,如果没有监听该事件,则请求connect方法的客户端将自动关闭。
  • connection 事件:建立新的TCP流时会触发该事件。
  • request 事件:每次有请求时都会触发。 每个连接可能有多个请求(在 HTTP Keep-Alive 连接的情况下)。
  • upgrade 事件:每次客户端请求 HTTP 升级时发出。 监听此事件是可选的,客户端无法坚持更改协议。

http.server方法

  • server.cose([callback]):停止服务器接受新连接。 请参见 net.Server.close()。
  • server.listen():启动 HTTP 服务器监听连接。 此方法与 net.Server 中的 server.listen() 相同。
  • server.setTimeout([msecs][,callback]):设置连接超时事件和回调函数。msecs默认为120000,也就是连接超时默认为2分钟。

http.server属性

  • server.headersTimeout:限制解析器等待接收完整 HTTP 请求头的时间,默认值为40000。
  • server.listening:<boolean> 表明服务器是否正在监听连接。
  • server.maxHeadersCount:限制最大传入请求头数。 如果设置为 0,则不会应用任何限制,默认值为2000。
  • server.timeout:设置连接超时事件。
  • server.keepAliveTimeout:设置服务端响应完最后一个响应后,在销毁套字节之前的非活动毫秒数,默认值为5000,即5秒。

http.ServerResponse 类

用于处理服务端响应客户端的http通讯模型。

http.ServerResponse事件

  • close 事件:底层连接被终止后触发。
  • finish 事件:响应发送后触发。

http.ServerResponse方法

  • response.addTrailers(headers):用于添加http响应报文尾部响应头,在response.write()后面、response.end()前面使用。
  • response.end([data[,encoding]][,callback]):该方法用于告诉服务,响应头和主体已经发送完毕。如果传入data(数据)和encoding(字符编码集),相当于response.write(data[,encoding])。callback回调函数在响应流完成以后调用。
  • response.flushHeaders()
  • response.getHeader(name):读取以排队但未发送出去的响应头的值,name为响应头名称。读取对应setHeader()添加的响应头。
  • response.getHeaderNames():读取响应报文的所有响应头的名称列表。注意读取出来的字母都是小写。
  • response.getHeaders():以键值对的方式读取所有响应头名称和值。
  • response.hasHeader(name):<boolean>如果当前在传出的响应头中设置了由 name 标识的响应头,则返回 true。 响应头名称匹配不区分大小写。
  • response.removeHeader(name):移除排队等待中的隐式发送的响应头。
  • response.setHeader(name,value):用于添加响应头。
  • response.setTimeout(msecs[,callback]):<response>将套接字的超时值设置为 msecs。 如果提供了回调,则会将其作为监听器添加到响应对象上的 'timeout' 事件中。
  • response.write(chunk[,encoding][,callback]):使用该方法给响应报文添加响应数据,通常被称为发送数据。
  • response.writeContinue():向客户端发送 HTTP/1.1 100 Continue 消息,表示应发送请求主体。
  • response.writeHead(statusCode[,statusMess][, headers]):配置响应报文的相应状态码。向请求发送响应头。 状态码是一个 3 位的 HTTP 状态码,如 404。 最后一个参数 headers 是响应头。 可以可选地将用户可读的 statusMessage 作为第二个参数。
  • response.writeProcessing():向客户端发送 HTTP/1.1 102 处理消息,表明可以发送请求主体。

http.ServerResponse属性

  • response.connection:用于获取http连接的底层net.socket对象,与response.socket属性指向同一个对象。
  • response.finished:<boolean>调用了response.end()方法后,该属性值被修改成true。
  • response.headersSent: <boolean>如果已发送响应头,则为 true,否则为 false。
  • response.sendDate:<boolean>默认值为true,表示在响应头中默认添加date响应头。
  • response.socket:用于获取http连接的底层net.socket对象。
  • response.statusCode:设置默认响应状态码。如果没有使用writeHead()设置相应码会将该默认响应码添加到相应报文中。比如可以设置为:404。
  • response.statusMessage:当响应头使用默认相应码状态码时,即上面一个statusCode的默认值被添加到相应头时,会将该属性值作为相应状态说明。(例如状态码200对应的是OK)。
  • response.writableEnded:<boolean>调用了response.end()方法后,该属性值设置为true。但该属性为true时并不代表相应被发送出去了,如果需要判断请求是否发送出去请使用response.writableFinished。
  • response.writableFinished:如果在触发 'finish' 事件之前,所有数据都已刷新到底层的系统,则为 true。也就是相应报文发送出去后被置为true。

 三、HTTP模块上的消息(message)

http.IncomingMessage 类

服务端与客户端收到的http请求或响应的解析对象,通常它们也被称为“消息”。

http.IncomingMessage事件

  • aborted 事件:当请求中止后触发该事件。
  • close 事件:当底层连接关闭后触发该事件。

http.IncomingMessage方法

  • message.destroy([error]):销毁当前请求,销毁后的请求,服务上response不会做任何响应,该方法可以传入一个Error(异常)对象,调用该方法后如果传入了Error(异常)对象会通过Error事件触发该异常。
  • message.setTimeout(msecs[,callback]):

http.IncomingMessage属性

  • message.aborted:<boolean>属性值为true时,表示请求已中止。
  • message.complete:<boolean>属性值为true时,表示已收到并成功解析完整的http消息。
  • message.headers:请求头或响应头对象,收到http请求或者响应以后会将请求头作为key/value(键/值)解析为一个对象赋给该属性。
  • message.httpVersion:<string>获取客户端请求的http版本号,例如:‘1.1’;还可以通过message.httpVersionMajor 是第一个整数, message.httpVersionMinor 是第二个整数。
  • message.method:获取请求方法的类型,仅在http.server获取的请求中有效。
  • message.rawHeaders:原始请求头/响应头的列表,与接收到的完全一致。键和值位于同一列表中。 它不是元组列表。 因此,偶数偏移是键值,奇数偏移是关联的值。例如:['Host', '127.0.0.1:12306','Connection','keep-alive'...]。
  • message.rawTrailers:
  • message.socket:获取http请求与响应相关链的net.socket对象,可以通过message.socket访问net.socket的任何方法和属性。比如:message.socket.address()获取当前消息的地址信息。
  • messave.statusCode:用于客户端获取服务响应报文的状态码。
  • messave.statusMessage:用于客户端获取服务响应说明,比如响应码200时的说明是“OK”。
  • message.trailes:由尾部消息头解析出来的对象,也就是由end()响应发出的http报文头。
  • message.url:<string>获取http请求头中的url,例如:GET /status?name=ryan HTTP/1.1\r\n 中的“/status?name=ryan”。这个rul包含了请求携带的数据,如果需要纯粹的rul还需要使用rul模块解析message.url。例如:url.parse(request.url).pathname;就可以获取到“/status”。

 四、HTTP模块上的代理(agent)与请求(request)

http.Agent类

Agent方法

  • new Agent([options]):如果需要配置代理的设置,需要自定义一个,因为http.request()使用默认的http.globalAgent 具有所有这些值且被设置为各自的默认值。通过new Agent([options])创建一个自定义的代理,options为自定义配置,可配置的选项有:

    keepAlive:<boolean>当属性值为true时(默认false)即使没有未完成的请求,也要保持套字节,被用于将来的请求而无需重新建立 TCP 连接。注意不要与http请求头connection的keep-alive值混洗,connection为keep-alive是配置http前请求为长连接的。Connection: keep-alive 请求头始终在使用代理时发送,除非明确指定 Connection 请求头、或者 keepAlive 和 maxSockets 选项分别设置为 false 和 Infinity,在这种情况下将会使用 Connection: close。 默认值: false。

    keepAliveMsecs:<number>当使用keepAlive选项时,指定保持套字节的延迟时间,默认为1000。若keepAlive选项配置为false或undefined时,则忽略keepAliveMsecs选项。

    maxSockets:<number>每个主机允许套字节的最大数量。默认值为Infinity,即无穷不限制。

    maxFreeSockets:<number>在空闲状态下保持打开的套字节的最大数量。该配置也需要是在keepAlive选项配置为true时生效。默认值为256。

    timeout:<number>配置套字节的超时时间,在套字节被连接之后设置该超时时间。

    1 //自定义http.Agent实例
    2 const http = require('http');
    3 const keepAliveAgent = new http.Agent({ keepAlive: true });
    4 options.agent = keepAliveAgent;
    5 http.request(options, onResponseCallback);
  • agent.createConnection(options[,callback]):用于生成HTTP请求的套字节或流。详细见官方文档
  • agent.keepSocketAlive(socket):这个方法封装了net.socket对象上的setKeepAlive(),当该方法返回一个假值时,销毁当前套字节,当前套字节不再保留给下一个请求。
  • agent.reuseSocket(socket,request):这个方法封装了net.socket对象上的ref(),可以用来取消销毁套字节操作,继续保留连接。
  • agent.destroy():用于销毁代理当前使用的所有套字节。
  • agent.getName(options):获取一组请求选项的唯一名称,以判定一个连接是否可以被重用。

Agent属性

  • agent.freeSockets:一个对象,其中包含当启用 keepAlive 时代理正在等待使用的套接字数组。 不要修改。
  • agent.maxFreeSockets:默认设置为 256。 对于启用了 keepAlive 的代理,这将设置在空闲状态下保持打开的最大套接字数。
  • agent.maxSockets:默认情况下设置为 Infinity。 决定代理可以为每个来源打开多少并发套接字。 来源是 agent.getName() 的返回值。
  • agent.requests:一个对象,包含尚未分配给套接字的请求队列。 不要修改。
  • agent.sockets:一个对象,包含当前代理正在使用的套接字数组。 不要修改。

http.ClientRequest类

request事件

  • abort 事件:当客户端中止请求时触发,该事件仅在第一次调用abort()时触发。
  • connect 事件:每次服务器使用connect()方法响应请求时都会触发。如果没有监听此事件,则收到connect()方法的客户端将关闭其连接。
  • continue 事件:当服务发送100 Continue HTTP响应时触发,通常是因为请求包含Expect: 100-continue。这时客户端应发送请求主体的指令。
  • information 事件:服务器发送 1xx 中间响应(不包括 101 Upgrade)时触发。此事件的监听器将会接收一个对象,该对象包含HTTP版本,状态码,状态消息,键值对请求头对象、以及具有原始请求头名称和值的数组。
  • response 事件:当收到此请求的响应时触发。此事件仅触发一次。
  • socket 事件:将套接字分配给此请求后触发。
  • timeout 事件:当底层套字节因不活动而超时时触发。这只会通知套接字已空闲。必须手动中止请求。
  • upgrade 事件:每次服务器响应升级请求时发出。如果没有监听此事件且响应状态码为101 Switching Protocols,则接收到升级响应头的客户端将关闭其连接。

request方法

  • request.abort():将请求标记为中止。调用此方法将导致响应中剩余的数据被丢弃并且套接字被销毁。
  • request.end([data[,encoding]][,callback]):完成发送请求。如果部分请求主体还未发送,则将它们刷新到流中。如果请求被分块,则发送终止符“0\r\n\r\n。【意思是将data作为请求主体添加到流中,如果没有data则表示结束请求发送终止符,待请求主体发送完以后调用回调函数】
  • request.flushHeaders():
  • request.getHeader(name):读取请求中的一个请求头,name为请求头的名称,然后返回该请求头的值。
  • request.removeHeader(name):删除已经定义到请求头对象中的请求头。
  • request.setHeader(name,value):为请求头对象设置的那个请求头的值。
  • request.setNoDelay([noDelay]):将套接字分配给此请求,如果该套接字处于连接状态,就会调用socket.setNoDelay()。意思是不会对发送数据进行缓冲,立即发送请求。
  • request.setSocketKeepAlive([enable][,initialDelay]):将套接字分配给此请求,如果套接字处于连接状态,就会调用socket.setKeepAlive()。意思是使用一个指定的套接字发送请求,并且可以配置套接字是否启用长连接。
  • request.setTimeout(timeout[,callback]):将套接字分配给此请求,如果套接字处于连接状态,就会调用socket.setTimeout()。意思是使用一个超时监听事件监听该请求,如果该请求超时会调用socket上的timeout事件。
  • request.write(chunk[,encoding][,callback]):发送请求主体数据块。

request属性

  • request.aborted:如果请求已中止,则该属性值被附为true。
  • request.connection:
  • request.finished:如果调用end(),属性值被附为true。如果通过http.get()发起的则自动调用end()方法。
  • request.maxHeadersCount:限制最大响应头数。如果设置为0,则不会应用任何限制。
  • request.path:请求路径。
  • request.socket:指向net上的socket套接字对象。
  • request.writableEnded:end()方法被调用之后,该属性被附为true。这仅仅请求已完成,并不代表接收到了数据。
  • request.writableFinished:如果服务确定相应发送完成之前,客户端的数据已经更新完毕,则该属性被附为true。这表明客户端收到了完整的相应数据。

 五、get请求与post请求的差异与示例

这里本来想写一个http请求的示例,但觉得没有多大意义,大把的文档手册和笔记中都有,对于初学者来说get与post请求的差异对于前端开发来说比较模糊,因为在前端看起来好像就只是一个配置参数的区别,但是实际上是因为请求报文的差异导致的,先从两个示例及报文来看:

1.get方法请求示例:

let xmlHttp = new XMLHttpRequest();
//get请求方法
xmlHttp.open("GET","/login?" + params,true);
xmlHttp.send(null);
xmlHttp.onreadystatechange = function(){
    if(xmlHttp["readyState"] === 4){
        if(xmlHttp["status"] === 200){
            console.log(xmlHttp["responseText"]);//{"userId":"qqq","userPassword":"123"}
        }
    }
}

get方法请求服务端解析:

let http = require("http");
http.createServer(function(request,response){
    let pathName = url.parse(request.url).pathname;
    let params = url.parse(request.url,true).query;
    response.writeHead(200);
    response.write(JSON.stringify(params));//这里将接收到的请求数据在发送回客户端
    response.end();
}).listen(12306);//端口自己看着办

2.post方法请求示例:

let xmlHttp = new XMLHttpRequest();
xmlHttp.open("POST","/login",true);
xmlHttp.setRequestHeader('Content-type','application/x-www-form-urlencoded');
xmlHttp.send(paramsJson);
xmlHttp.onreadystatechange = function(){
    if(xmlHttp["readyState"] === 4){
        if(xmlHttp["status"] === 200){
            console.log(xmlHttp["responseText"]);
        }
    }
}

post方法请求服务端解析:

let http = require("http");
http.createServer(function(request,response){
    let pathName = url.parse(request.url).pathname;
    let params = url.parse(request.url,true).query;
    request.on("data",function (data) {
         console.log(data.toString());//注意nodejs默认解析出来的是buffer类型数据
         response.writeHead(200);
         response.write(data.toString());
         response.end();
    });
}).listen(12306);

完整示例代码:

  1 //文件结构
  2 page
  3     --login.html
  4 config.js
  5 index.js
  6 server.config
  7 
  8 //index.js
  9 let http = require("http");
 10 let url = require("url");
 11 let fs = require("fs");
 12 
 13 let serverConfig = require("./config.js");//解析配置文件模块
 14 
 15 http.createServer(function(request,response){
 16     let pathName = url.parse(request.url).pathname;
 17     let params = url.parse(request.url,true).query;
 18     let isStatic = isStaticsRequest(pathName);
 19     console.log(request.url);
 20     if(isStatic){
 21         try{
 22             let data = fs.readFileSync(serverConfig["page_path"] + pathName);
 23             response.writeHead(200);
 24             response.write(data);
 25             response.end();
 26         }catch (e) {
 27             response.writeHead(404);
 28             response.write("请求资源出错!")
 29             response.end();
 30         }
 31     }else{
 32         request.on("data",function (data) {
 33             console.log(data.toString());
 34             response.writeHead(200);
 35             response.write(data.toString());
 36             response.end();
 37         });
 38         // response.writeHead(200);
 39         // response.write(JSON.stringify(params));
 40         // response.end();
 41     }
 42 }).listen(12306);
 43 
 44 
 45 //判断是否请求静态资源的工具方法
 46 function isStaticsRequest(pathName){
 47     for(let i = 0; i < serverConfig["staticFileType"].length; i++){
 48         let temp = serverConfig["staticFileType"][i];
 49         if(pathName.indexOf(temp) !== -1 && pathName.indexOf(temp) === pathName.length - temp.length){
 50             return true;
 51         }
 52     }
 53     return false;
 54 }
 55 
 56 //server.config
 57 port=12306
 58 static_file_type=.html|.js|.css|.json|.jpg|.gif|.ico
 59 page_path=page
 60 
 61 //config.js
 62 //自定义读取配置文件模块
 63 let fs=require("fs");
 64 
 65 function analysisConfig(configFile){
 66     let obj = {};
 67     let arr = configFile.toString().split("\r\n");
 68     for(let i = 0; i < arr.length; i++){
 69         let item = arr[i].split("=");
 70         if(item[0] === "static_file_type"){
 71             obj["staticFileType"] = item[1].split("|");
 72         }else{
 73             obj[item[0]] = item[1];
 74         }
 75     }
 76     return obj;
 77 }
 78 
 79 let configFile, configObj = {};
 80 
 81 try{
 82     configFile = fs.readFileSync("./server.config");
 83     configObj = analysisConfig(configFile);
 84 }catch (e) {
 85     console.log("解析server.config配置文件出错:",e);
 86 }
 87 module.exports = configObj;
 88 
 89 //login.html
 90 <!doctype html>
 91 <html lang="en">
 92 <head>
 93     <meta charset="UTF-8">
 94     <meta name="viewport"
 95           content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
 96     <meta http-equiv="X-UA-Compatible" content="ie=edge">
 97     <title>Document</title>
 98 </head>
 99 <body>
100     <h3>测试get与post请求</h3>
101     <p>
102         <span></span>账号:<input id="userId" type="text">
103         <span>密码:</span><input id="userPassword" type="password">
104         <input type="submit" value="登入" onclick="login()">
105     </p>
106     <script>
107         function login(){
108             let userIdValue = document.getElementById("userId").value;
109             let userPasswordValue = document.getElementById("userPassword").value;
110             let params = "userId=" + userIdValue + "&userPassword=" + userPasswordValue;
111             let paramsJson =JSON.stringify({userId:userIdValue,userPassword:userPasswordValue});
112             let xmlHttp = new XMLHttpRequest();
113             //get请求方法
114             // xmlHttp.open("GET","/login?" + params,true);
115             //post请求方法
116             xmlHttp.open("POST","/login",true);
117             xmlHttp.setRequestHeader('Content-type','application/x-www-form-urlencoded');
118             xmlHttp.send(paramsJson);
119 
120             // xmlHttp.send(null);
121             xmlHttp.onreadystatechange = function(){
122                 if(xmlHttp["readyState"] === 4){
123                     if(xmlHttp["status"] === 200){
124                         console.log(xmlHttp["responseText"]);
125                     }
126                 }
127             }
128         }
129     </script>
130 </body>
131 </html>
View Code

3.get与post的区别是什么?

3.1从API角度来看:

从浏览器支持的ajax来看,除了open的第一个参数[GET | POST],然后post方法请求的send()携带提交的数据;然后post方法请求还需要使用setRequestHeader()添加指定的报文主体内容编码格式类型,示例中使用了application/x-www-form-urlencoded,但提交不同数据需要采用不同的类型,这是告诉服务器如何解析保本主体中的数据内容,详细可以了解这篇博客:https://www.cnblogs.com/coce/p/9720285.html。从nodejs的服务端来看,get提交的数据使用request对象上的url中解析,url模块可以直接通过url.parse(url).pathname和url.parse(url).query中解析出路径和路径后面携带的参数。然后post提交的数据需要通过request的对象上data事件的回调函数的参数获取,这些可以直观的在示例代码中看到。

3.2从报文角度来看:

 get方法请求不包含保本主体部分,只有报文起始行[方法  路径 协议版本]和请求头部。post方法请求除了包文本起始行和请求头部,还必然会有请求主体。

3.3从协议标准以及平台实现的角度来看:

get请求数据通过?拼接在url之后,通过&连接多个数据元,如果是中文/其他字符转换成base64编码格式,如有空格转换成+,这并不是get方法的所特有,post方法同样可以在url后面拼接数据,通过?和&的连接方式也并非是协议的标准,而是大多数服务采用的通常格式,然后可以实现通用的协议解析API。将中文和其他字符转换成base64编码格式是因为HTTP报文采用ASCII编码,在ASCII编码是基于拉丁字母的编码系统,不包含中文和特殊字符,所以base64相当于只是中间码。

url中的数据最多只能是1024字节,这个限制是浏览器或者服务器给添加的,http协议并没有对url长度进行限制。

通常所说的post请求发送数据没有大小限制是因为,post请求通常使用包文本主体作为数据的载体,而不是使用url,报文主体如果不使用content-length头部限制长度就不会限制数据长度。即便post请求同样可以使用url作为数据载体,post如果使用url作为数据载体同样会受到长度限制。

get产生的url地址可以被收藏到浏览器书签,而post不能。

get的请求参数会被完整的保留在浏览器历史记录中,而post中的参数不会,这仅仅只是说post在不使用url作为数据载体的时候。就像get请求参数会完整的暴露在浏览器地址栏一样。

3.4从网络请求与响应操作角度来看:

在浏览器中使用post请求会将报文头部和报文主体分开,先发送报文头部等待服务响应100状态码然后再发送报文主体,这仅仅只是浏览器的实现方式,而不是http协议标准。(基于chrome浏览器测试会分开发送)。

get请求的资源浏览器回退时不会再次发起网络请求,而post请求当浏览器回退时会再次发送网络请求(这里可能出现重复提交)。

3.5从安全角度来看:

谈论get和post请求安全问题就好像一个伪命题,http本身采用的是明文传输,在任何网络节点上都可能直接的获取到完整的明文数据。所谓的安全仅仅只能是说在非技术层的浏览器地址栏和历史记录中是可见的,从技术层面来说无论get还是post携带的数据都可以被查阅获取,如果需要数据安全就只能采用https加密传送协议。

3.6get与post区别对照表

分类GETPOST
后退按钮/刷新 无害 数据会被重新提交(浏览器应该告知用户数据会被重新提交)。
书签 可收藏为书签 不可收藏为书签
缓存 能被缓存 不能缓存
编码类型 application/x-www-form-urlencoded application/x-www-form-urlencoded 或 multipart/form-data。为二进制数据使用多重编码。
历史 参数保留在浏览器历史中。 参数不会保存在浏览器历史中。
对数据长度的限制 是的。当发送数据时,GET 方法向 URL 添加数据;URL 的长度是受限制的(URL 的最大长度是 2048 个字符)。 无限制。
对数据类型的限制 只允许 ASCII 字符。 没有限制。也允许二进制数据。
安全性 与 POST 相比,GET 的安全性较差,因为所发送的数据是 URL 的一部分。在发送密码或其他敏感信息时绝不要使用 GET ! POST 比 GET 更安全,因为参数不会被保存在浏览器历史或 web 服务器日志中。
可见性 数据在 URL 中对所有人都是可见的。 数据不会显示在 URL 中。

 六、登入跳转问题(重定向)

这里仅对页面和服务端的网络请求和响应的重定向做介绍,不涉及内容内容发布与分发的HTTP代理重定向内容。

6.1表单请求跳转重定向:

//html代码
//from标签中使用action指定请求接口,method指定请求方式
<form method="post" action="/classAdminiLogin">
    <div class="a"><span>账号:</span><input name="account" type="text"></div>
    <div><span>密码:</span><input name="password" type="password"></div>
    <div><input class="loginBut" type="submit" value="登入"></div>
</form>

//服务端js代码
//响应状态码302,并通过location报文头部字段指定跳转的路径
response.writeHead(302,{"location":"/html/studentInfor.html"});
response.end();

通过form表单请求可以省略手动写ajax请求,但也有一个弊端就是但请求失败时不好处理,不利于交换。比较常用的方式还是通过ajax请求来实现:

6.2ajax请求跳转

 1 ...
 2 <div><button class="loginBut">登入</button></div>
 3 //ajax中的关键代码:
 4 if(xmlHttp.responseText === "ok"){//假设请求成功服务返回数据“ok”
 5     location.herf = "/html/studentInfor.html"
 6 }else{
 7     //这里可以处理请求失败的相关业务
 8 }
 9 
10 //服务端js代码
11 response.writeHead(200);
12 response.write("ok");
13 response.end();
posted @ 2019-12-09 11:24  他乡踏雪  阅读(1309)  评论(0编辑  收藏  举报