NodeJS HTTP

发布于 2024-07-28 11:19:00 字数 7760 浏览 43 评论 0

目前世界上运行最良好的分布式集群,莫过于当前的万维网 (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

methodsCRUD幂等缓存
GETRead
POSTCreate  
PUTUpdate/Replace 
PATCHUpdate/Modify  
DELETEDelete 

GET 和 POST 有什么区别?

网上有很多讲这个的,比如从书签,url 等前端的角度去看他们的区别这里不赘述. 而从后端的角度看,前两年出来一个 《GET 和 POST 没有区别》(出处不好考究,就没贴了) 的文章比较有名,早在我刚学 PHP 的时候也有过这种疑惑,刚学 Node 的时候发现不能像 PHP 那样同时处理 GET 和 POST 的时候还很不适应. 后来接触 RESTful 才意识到,这两个东西最根本的差别是语义,引申了看,协议 (protocol) 这种东西就是人与人之间协商的约定,什么行为是什么作用都是"约定"好的,而不是强制使用的,非要把 GET 当 POST 这样不遵守约定的做法我们也爱莫能助。

跑题了,简而言之,讨论这二者的区别最好从 RESTful 提倡的语义角度来讲比较符合当代程序员的逼格比较合理。

POST 和 PUT 有什么区别?

POST 是新建 (create) 资源,非幂等,同一个请求如果重复 POST 会新建多个资源. PUT 是 Update/Replace,幂等,同一个 PUT 请求重复操作会得到同样的结果。

headers

HTTP headers 是在进行 HTTP 请求的交互过程中互相支会对方一些信息的主要字段。比如请求 (Request) 的时候告诉服务端自己能接受的各项参数,以及之前就存在本地的一些数据等. 详细各位可以参见 wikipedia:

cookie 与 session 的区别?服务端如何清除 cookie?

主要区别在于,session 存在服务端,cookie 存在客户端. session 比 cookie 更安全. 而且 cookie 不一定一直能用 (可能被浏览器关掉). 服务端可以通过设置 cookie 的值为空并设置一个及时的 expires 来清除存在客户端上的 cookie.

什么是跨域请求? 如何允许跨域?

出于安全考虑,默认情况下使用 XMLHttpRequest 和 Fetch 发起 HTTP 请求必须遵守同源策略,即只能向相同 host 请求 (host = hostname:port)注[1],向不同 host 的请求被称作跨域请求 (cross-origin HTTP request),可以通过设置 CORS headersAccess-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>

详见 JavaScript Script Error.

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(不包括)版本中发现一个问题:

    1. 你将 keepAlive 设置为 true 时,socket 有复用
    1. 即使 keepAlive 没有设置成 true 但是长时间内有大量请求时,同样有复用 socket (复用情况参见 @zcs19871221解析 )

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 错误。

Node.js 中源码的情况:

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

刘备忘录

暂无简介

文章
评论
417 人气
更多

推荐作者

櫻之舞

文章 0 评论 0

弥枳

文章 0 评论 0

m2429

文章 0 评论 0

野却迷人

文章 0 评论 0

我怀念的。

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文