网络编程http/https/http2/websocket

2019-11-06  本文已影响0人  LM林慕

此文项目代码:https://github.com/bei-yang/I-want-to-be-an-architect
码字不易,辛苦点个star,感谢!

引言


此篇文章主要涉及以下内容:

  1. HTTP协议
  2. http服务使用
  3. 前后端通信技术ajaxwebsocket
  4. 常见web问题:跨域、session
  5. 实现一个爬虫程序
  6. TCP协议 - 实现一个即时通讯IM
  7. https
  8. http2

HTTP协议


ISO七层网络协议

const http = require("http");
const fs = require("fs");

http
  .createServer((req, res) => {
    const { method, url } = req;
    if (method === "GET" && url === "/") {
      fs.readFile("./index.html", (err, data) => {
        res.setHeader("Content-Type", "text/html");
        res.end(data);
      });
    } else if (method === "GET" && url === "/users") {
      res.setHeader("Content-Type", "application/json");
      red.end(JSON.stringify([{ name: "tom", age: 20 }]));
    }
  })
  .listen(3000);
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
axios
.get("/users")
   .then(res => res.data)
   .then(users => console.log(users));
</script>
// 1.创建http-server-2.js,使用端口3001
server.listen(3001);
// 2.index.html中请求位于3000服务器的端口
axios.get("http://localhost:3000/users")
  1. 浏览器抛出跨域错误
  1. 常用解决方案

    • JSONP(JSON with Padding),前端+后端方案,绕过跨域

    前端构造script标签请求指定URL(由script标签发出的GET请求不受同源策略限制),服务器返回一个函数执行语句,该函数名称通常由查询参callback的值决定,函数的参数为服务器返回的json数据。该函数在前端执行后即可获取数据。

    • 代理服务器

    请求同源服务器,通过该服务器转发请求至目标服务器,得到结果再转发给前端。前端开发中测试服务器的代理功能就是采用的该解决方案,但是最终发布上线时如果web应用和接口服务器不在一起仍会跨域。

    • CORS(Cross Origin Resource Share) - 跨域资源共享,后端方案,解决跨域。
      原理:cors是w3c规范,真正意义上解决跨域问题。它需要服务器对请求进行检查并对响应头做相应处理,从而允许跨域请求。
      具体实现:

      1. 响应简单请求:动词为get/post/head,没有自定义请求头,Content-Type是application/x-www-form-urlencoded,multipart/form-data或text/plain之一,通过添加以下响应头解决:
      res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3001')
      
      1. 响应preflight请求,需要响应浏览器发出的options请求(预检请求),并根据情况设置响应头:
      else if (method == "OPTIONS" && url == "/users") {
       res.writeHead(200, {
        "Access-Control-Allow-Origin":       "http://localhost:3001",
        "Access-Control-Allow-Headers": "X-Token,Content-Type",
        "Access-Control-Allow-Methods": "PUT"
      });
       res.end();
      }
      

      该案例中可以通过添加自定义的x-token请求头使请求变为preflight请求

      // index.html
      axios.get("http://localhost:3000/users", {headers:{'X-
      Token':'jilei'}})
      

      则服务器需要允许x-token,若请求为POST,还传递了参数:

      // index.html
      axios.post("http://localhost:3000/users", {foo:'bar'}, {headers:
      {'X-Token':'jilei'}})
      // http-server.js
      else if ((method == "GET" || method == "POST") && url ==
      "/users") {}
      

      则服务器还需要允许content-type请求头

      1. 如果要携带cookie信息,则请求变为credential请求:
      // 预检options中和/users接口中均需添加
      res.setHeader('Access-Control-Allow-Credentials', 'true');
      

实现一个爬虫


原理:服务器模拟客户端发送请求到目标服务器获取页面内容并解析,获取其中关注部分的数据。

const originRequest = require("request");
const cheerio = require("cheerio");
const iconv = require("iconv-lite");

function request(url, callback) {
  const options = {
    url: url,
    encoding: null
  };
  originRequest(url, callback);
}
// 爬取电影天堂的电影名
for (let i = 100553; i < 100563; i++) {
  const url = `https://www.dy2018.com/i/${i}.html`;
  request(url, function(err, res, body) {
    const html = iconv.decode(body, "gb2312");
    const $ = cheerio.load(html);
    console.log($(".title_all h1").text());
  });
}

实现一个实时聊天程序


const net = require("net");
const chatServer = net.createServer(),
  clientList = [];
chatServer.on("connection", function(client) {
  client.write("Hi!\n");
  clientList.push(client);
  client.on("data", function(data) {
    clientList.forEach(v => {
      v.write(data);
    });
  });
});
chatServer.listen(9000);

通过Telnet连接服务器

telnet localhost 9000

curl -v http://www.baidu.com

<html>
<head>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
  <div id="app">
    <input v-model="message">
    <button v-on:click="send">发送</button>
    <button v-on:click="clear">清空</button>
    <div v-for="item in list">{{item}}</div>
  </div>
  <script>
    const host = 'http://localhost:3000'
    var app = new Vue({
      el: '#app',
      data: {
        list: [],
        message: 'Hello Vue!'
     },
      methods: {
        send: async function () {
          let res = await axios.post(host + '/send', {
            message: this.message
         })
          this.list = res.data
       },
        clear: async function () {
          let res = await axios.post(host + '/clear')
          this.list = res.data
       }
     },
      mounted: function () {
        setInterval(async () => {
          const res = await axios.get(host + '/list')
          this.list = res.data
       }, 1000);
     }
   });
  </script>
</body>
</html>
const express = require("express");
const app = express();
const bodyParser = require("body-parser");
const path = require("path");
app.use(bodyParser.json());
const list = ["ccc", "bbbb"];
app.get("/chat", (req, res) => {
  res.sendFile(path.resolve("./chat.html"));
});
app.get("/list", (req, res) => {
  res.end(JSON.stringify(list));
});
app.post("/send", (req, res) => {
  list.push(req.body.message);
  res.end(JSON.stringify(list));
});
app.post("/clear", (req, res) => {
  list.length = 0;
  res.end(JSON.stringify(list));
});

app.listen(3000);
// src/im/index.js
const io = require("socket.io")(server);
io.on("connection", socket => {
  console.log("io connection...");
  socket.on("chat", msg => {});
});

app.post("/send", (req, res) => {
  list.push(req.body.message);
  // socketIO 增加
  io.emit("chat", list);
  res.end(JSON.stringify(list));
});

// src/im/index.html
mounted:function(){
  //http轮询
    // setInterval(async () => {
  //   const res = await axios.get(host + '/list')
  //   this.list = res.data
 // }, 1000);

  //websocket方式
  const socket = io(host)
  socket.on('chat',list=>{
    this.list=list
  })
}

Socket.IO库特点:

  • 源于HTML5标准
  • 支持优雅降级
    • WebSocket
    • WebSocket over Flash
    • XHR Polling
    • XHR Multipart Streaming
    • Forever Iframe
    • JSONP Polling

Https(安全文章中再聊)


# 创建私钥
openssl genrsa -out privatekey.pem 1024
# 创建证书签名请求
openssl req -new -key privatekey.pem -out certrequest.csr
# 获取证书,线上证书需要经过证书授证中心签名的文件;下面只创建一个学习使用证书
openssl x509 -req -in certrequest.csr -signkey privatekey.pem -out certificate.pem
# 创建pfx文件
openssl pkcs12 -export -in certificate.pem -inkey privatekey.pem -out
certificate.pfx

Http2(优化文章中再聊)


你的赞是我前进的动力

求赞,求评论,求转发...

上一篇 下一篇

猜你喜欢

热点阅读