NodeJS HTTP
目前世界上运行最良好的分布式集群,莫过于当前的万维网 (http servers) 了. 目前前端工程师也都是靠 HTTP 协议吃饭的,所以 2-3 年的前端同学都应该对 HTTP 有比较深的理解了,所以这里不做太多的赘述. 推荐书籍 《图解 HTTP》 ,博客 HTTP 协议入门 。
另外最近几年开始大家对 HTTP 的面试的考察也渐渐偏向 理解 RESTful 架构 。简单的说,RESTful 是把每个 URI 当做资源 (Resources),通过 method 作为动词来对资源做不同的动作,然后服务器返回 status 来得知资源状态的变化 (State Transfer)。
method/status
因为 HTTP 的方法 (method) 与状态码 (status) 讲解太常见,你可以使用如下代码打印出来自己看 Node.js 官方定义的,完整的就不列举了。
const http = require('http');
console.log(http.METHODS);
console.log(http.STATUS_CODES);
一个常见的 method 列表,关于这些 method 在 RESTful 中的一些应用的详细可以参见 Using HTTP Methods for RESTful Services
methods | CRUD | 幂等 | 缓存 |
---|---|---|---|
GET | Read | ✓ | ✓ |
POST | Create | ||
PUT | Update/Replace | ✓ | |
PATCH | Update/Modify | ||
DELETE | Delete | ✓ |
GET 和 POST 有什么区别?
网上有很多讲这个的,比如从书签,url 等前端的角度去看他们的区别这里不赘述. 而从后端的角度看,前两年出来一个 《GET 和 POST 没有区别》(出处不好考究,就没贴了) 的文章比较有名,早在我刚学 PHP 的时候也有过这种疑惑,刚学 Node 的时候发现不能像 PHP 那样同时处理 GET 和 POST 的时候还很不适应. 后来接触 RESTful 才意识到,这两个东西最根本的差别是语义,引申了看,协议 (protocol) 这种东西就是人与人之间协商的约定,什么行为是什么作用都是"约定"好的,而不是强制使用的,非要把 GET 当 POST 这样不遵守约定的做法我们也爱莫能助。
跑题了,简而言之,讨论这二者的区别最好从 RESTful 提倡的语义角度来讲比较符合当代程序员的逼格比较合理。
POST 是新建 (create) 资源,非幂等,同一个请求如果重复 POST 会新建多个资源. PUT 是 Update/Replace,幂等,同一个 PUT 请求重复操作会得到同样的结果。
headers
HTTP headers 是在进行 HTTP 请求的交互过程中互相支会对方一些信息的主要字段。比如请求 (Request) 的时候告诉服务端自己能接受的各项参数,以及之前就存在本地的一些数据等. 详细各位可以参见 wikipedia:
主要区别在于,session 存在服务端,cookie 存在客户端. session 比 cookie 更安全. 而且 cookie 不一定一直能用 (可能被浏览器关掉). 服务端可以通过设置 cookie 的值为空并设置一个及时的 expires 来清除存在客户端上的 cookie.
出于安全考虑,默认情况下使用 XMLHttpRequest 和 Fetch 发起 HTTP 请求必须遵守同源策略,即只能向相同 host 请求 (host = hostname:port)注[1],向不同 host 的请求被称作跨域请求 (cross-origin HTTP request),可以通过设置 CORS headers 即 Access-Control-Allow-
系列来允许跨域,例如:
location ~* ^/(?:v1|_) {
if ($request_method = OPTIONS) { return 200 ''; }
header_filter_by_lua '
ngx.header["Access-Control-Allow-Origin"] = ngx.var.http_origin; # 这样相当于允许所有来源了
ngx.header["Access-Control-Allow-Methods"] = "GET, POST, PUT, DELETE, PATCH, OPTIONS";
ngx.header["Access-Control-Allow-Credentials"] = "true";
ngx.header["Access-Control-Allow-Headers"] = "Content-Type";
';
proxy_pass http://localhost:3001 ;
}
注[1]:同源除了相同 host 也包括相同协议. 所以即使 host 相同,从 HTTP 到 HTTPS 也属于跨域,见 讨论。
Script error.
是什么错误?如何拿到更详细的信息?
接上题,由于同源性策略 (CORS),如果你引用的 js 脚本所在的域与当前域不同,那么浏览器会把 onError 中的 msg 替换为 Script error.
要拿到详细错误的方法,处理配好 Access-Control-Allow-Origin
还有在引用脚本的时候指定 crossorigin
例如:
<script src="http://another-domain.com/app.js" crossorigin="anonymous"></script>
Agent
Node.js 中的 http.Agent
用于池化 HTTP 客户端请求的 socket (pooling sockets used in HTTP client requests). 也就是复用 HTTP 请求时候的 socket. 如果你没有指定 Agent 的话,默认用的是 http.globalAgent
。
另外,目前在 Node.js 的 6.8.1(包括)到 6.10(不包括)版本中发现一个问题:
- 你将 keepAlive 设置为
true
时,socket 有复用
- 你将 keepAlive 设置为
- 即使 keepAlive 没有设置成
true
但是长时间内有大量请求时,同样有复用 socket (复用情况参见 @zcs19871221 的 解析 )
- 即使 keepAlive 没有设置成
1 和 2 这两种情况下,一旦设置了 request timeout,由于 socket 一直未销毁,如果你在请求完成以后没有注意清除该事件,会导致事件重复监听,且该事件闭包引用了 req,会导致内存泄漏。
如果有疑虑的话可以参见 Node 官方讨论的 issue 以及引入此 bug 的 commit ,如果此处描述有疑问可以在本 repo 的 issue 中指出.
socket hang up
hang up 有挂断的意思,socket hang up 也可以理解为 socket 被挂断,在 Node.js 中当你要 response 一个请求的时候,发现该这个 socket 已经被 挂断,就会就会报 socket hang up 错误。
function socketCloseListener() {
var socket = this;
var req = socket._httpMessage;
// Pull through final chunk, if anything is buffered.
// the ondata function will handle it properly, and this
// is a no-op if no final chunk remains.
socket.read();
// NOTE: It's important to get parser here, because it could be freed by
// the `socketOnData`.
var parser = socket.parser;
req.emit('close');
if (req.res && req.res.readable) {
// Socket closed before we emitted 'end' below.
req.res.emit('aborted');
var res = req.res;
res.on('end', function() {
res.emit('close');
});
res.push(null);
} else if (!req.res && !req.socket._hadError) {
// This socket error fired before we started to
// receive a response. The error needs to
// fire on the request.
req.emit('error', createHangUpError()); // <------------------- socket hang up
req.socket._hadError = true;
}
// Too bad. That output wasn't getting written.
// This is pretty terrible that it doesn't raise an error.
// Fixed better in v0.10
if (req.output)
req.output.length = 0;
if (req.outputEncodings)
req.outputEncodings.length = 0;
if (parser) {
parser.finish();
freeParser(parser, req, socket);
}
}
典型的情况是用户使用浏览器,请求的时间有点长,然后用户简单的按了一下 F5 刷新页面,这个操作会让浏览器取消之前的请求,然后导致服务端 throw 了一个 socket hang up。
详见万能的 stackoverflow:NodeJS - What does “socket hang up” actually mean?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

上一篇: NodeJS UDP
下一篇: 彻底找到 Tomcat 启动速度慢的元凶
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论