【Node.js】http

基本使用

import http from 'http'
// 创建本地服务器接收数据
const server = http.createServer((req, res) => {
  console.log(req.url)
  res.writeHead(200, { 
    'Content-Type': 'application/json' 
    // 'Content-Type': 'text/html;charset=utf-8'  // 将内容以 html 标签和 utf-8 的形式展示到网页上 
  })
  // write 中的内容直接展示到网页上
  // res.write('hello')
  res.end(JSON.stringify({
    data: "hello"
  }))
})
server.listen(8000,()=> {
  console.log("server is running")
})

响应内容出现中文乱码解决:

res..setHeader('content-type','text/html;charset=utf-8')

如果端口被其他程序占用,可以使用资源监视器找到占用端口的程序,然后使用任务管理器关闭对应的程序.

/**
 * 目标:基于 http 模块创建 Web 服务程序
 *  1.1 加载 http 模块,创建 Web 服务对象
 *  1.2 监听 request 请求事件,设置响应头和响应体
 *  1.3 配置端口号并启动 Web 服务
 *  1.4 浏览器请求(http://localhost:3000)测试
 */
// 1.1 加载 http 模块,创建 Web 服务对象
const http = require('http')
const server = http.createServer()
// 1.2 监听 request 请求事件,设置响应头和响应体
server.on('request', (req, res) => {
  // 设置响应头-内容类型-普通文本以及中文编码格式
  res.setHeader('Content-Type', 'text/plain;charset=utf-8')
  // 设置响应体内容,结束本次请求与响应
  res.end('欢迎使用 Node.js 和 http 模块创建的 Web 服务')
})
// 1.3 配置端口号并启动 Web 服务
server.listen(3000, () => {
  console.log('Web 服务启动成功了')
})

获取 http 请求报文

在这里插入图片描述
注意事项:

  1. request.url 只能获取路径以及查询字符串,无法获取 URL 中的域名以及协议的内容
  2. request.headers 将请求信息转化成一个对象,并将属性名都转化成了『小写』
  3. 关于路径:如果访问网站的时候,只填写了 IP 地址或者是域名信息,此时请求的路径为 /
  4. 关于 favicon.ico:这个请求是属于浏览器自动发送的请求

获取 http 响应报文

在这里插入图片描述

资源类型(MIME)

媒体类型(通常称为 Multipurpose Internet Mail Extensions 或 MIME 类型 )是一种标准,用来表示文档、文件或字节流的性质和格式。
mime 类型结构: [type]/[subType]

例如: text/html text/css image/jpeg image/png application/json

HTTP 服务可以设置响应头 Content-Type 来表明响应体的 MIME 类型,浏览器会根据该类型决定如何处理资源。

下面是常见文件对应的 mime 类型

  • html: ‘text/html’,
  • css: ‘text/css’,
  • js: ‘text/javascript’,
  • png: ‘image/png’,
  • jpg: ‘image/jpeg’,
  • gif: ‘image/gif’,
  • mp4: ‘video/mp4’,
  • mp3: ‘audio/mpeg’,
  • json: ‘application/json’

对于未知的资源类型,可以选择 application/octet-stream 类型,浏览器在遇到该类型的响应时,会对响应体内容进行独立存储,也就是我们常见的下载效果。

GET 请求的情况:

  • 在地址栏直接输入 url 访问
  • 点击 a 链接
  • link 标签引入 css
  • script 标签引入 js
  • img 标签引入图片
  • form 标签中的 method 为 get (不区分大小写)
  • ajax 中的 get 请求

POST 请求的情况:

  • form 标签中的 method 为 post(不区分大小写)
  • AJAX 的 post 请求

1.1 解决跨域问题

接口 jsonp 解决跨域

// server.js
const http = require('http')
const url = require('url')

const app = http.createServer((req, res) => {
  let urlObj = url.parse(req.url, true)
  console.log(urlObj.query.callback)
  switch (urlObj.pathname) {
    case '/api/user':
      res.end(`${urlObj.query.callback}(${JSON.stringify({name:'xxx',age:18})})`)
      break
    default:
      res.end('404.')
      break
  }
})

app.listen(3000, () => {
  console.log('localhost:3000')
})
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <script>
    const oscript = document.createElement('script');
    oscript.src = 'http://localhost:3000/api/user?callback=test';
    document.body.appendChild(oscript);
    function test(obj) {
      console.log(obj)
    }
  </script>

</body>

</html>

CORS 解决跨域

// server.js
const http = require('http')
const url = require('url')

const app = http.createServer((req, res) => {
  let urlObj = url.parse(req.url, true)
  // console.log(urlObj.query.callback)
  res.writeHead(200, {
    'Content-Type': 'application/json; charset=utf-8',
    // CORS 头
    'Access-Control-Allow-Origin': '*'
  })
  switch (urlObj.pathname) {
    case '/api/user':
      res.end(`${JSON.stringify({ name: 'xxx', age: 18 })}`)
      break
    default:
      res.end('404.')
      break
  }
})

app.listen(3000, () => {
  console.log('localhost:3000')
})
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <script>
    fetch('http://localhost:3000/api/user')
    .then(res=>res.json())
    .then(res=>console.log(res))
  </script>

</body>

</html>

通过 cors 解决跨域问题,我们也可以直接使用 cors 这个库,而且这个库有它先天的优势。

前端 反向代理只能在开发环境进行跨域,部署后不能跨域。
部署后可以在 Nginx 中配置代理,但是流程较为繁琐。

使用 cors 非常简单,原理就是上面的添加 Access-Control-Allow-Origin 响应头,开发阶段和部署后均能使用。

https://www.npmjs.com/package/cors

1.2 web服务器

get

<!-- index.html -->
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <script>
    fetch('http://localhost:3000/api/user')
    .then(res=>res.json())
    .then(res=>console.log(res))
  </script>
</body>

</html>
// get.js
const http = require('http')
const https =  require('https')
const url = require('url')

const app = http.createServer((req, res) => {
  let urlObj = url.parse(req.url, true)
  // console.log(urlObj.query.callback)
  res.writeHead(200, {
    'Content-Type': 'application/json; charset=utf-8',
    // CORS 头
    'Access-Control-Allow-Origin': '*'
  })
  switch (urlObj.pathname) {
    case '/api/user':
      // 现在作为客户端 去猫眼api请求数据
      // 注意协议要统一:https还是http
      httpget(res)
      break
    default:
      res.end('404.')
      break
  }
})
app.listen(3000, () => {
  console.log('localhost:3000')
})
function httpget(response) {
  let data = ''
  https.get(`https://i.maoyan.com/api/mmdb/movie/v3/list/hot.json?ct=%E7%9F%B3%E5%AE%B6%E5%BA%84&ci=76&channelId=4`,res => {
    // data 是一份一份的数据收集,end 是最终收集到的所有数据
    res.on('data', chunk => {
      data += chunk
    })
    res.on('end', () => {
      console.log(data)
      response.end(data)
    })
  })
}

另一种写法:

// get.js
const http = require('http')
const https =  require('https')
const url = require('url')

const app = http.createServer((req, res) => {
  let urlObj = url.parse(req.url, true)
  // console.log(urlObj.query.callback)
  res.writeHead(200, {
    'Content-Type': 'application/json; charset=utf-8',
    // CORS 头
    'Access-Control-Allow-Origin': '*'
  })
  switch (urlObj.pathname) {
    case '/api/user':
      // 现在作为客户端 去猫眼api请求数据
      // 注意协议要统一:https还是http
      // data 收集好的时候调用内部传入的 cb 函数
      httpget((data)=> {
        res.end(data)
      })
      break
    default:
      res.end('404.')
      break
  }
})
app.listen(3000, () => {
  console.log('localhost:3000')
})
function httpget(cb) {
  let data = ''
  https.get(`https://i.maoyan.com/api/mmdb/movie/v3/list/hot.json?ct=%E7%9F%B3%E5%AE%B6%E5%BA%84&ci=76&channelId=4`,res => {
    // data 是一份一份的数据收集,end 是最终收集到的所有数据
    res.on('data', chunk => {
      data += chunk
    })
    res.on('end', () => {
      console.log(data)
      cb(data)
    })
  })
}

post

<!-- index.html -->
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <script>
    fetch('http://localhost:3000/api/user')
    .then(res=>res.json())
    .then(res=>console.log(res))
  </script>

</body>

</html>
// post.js
const http = require('http')
const https = require('https')
const url = require('url')

const app = http.createServer((req, res) => {
  let urlObj = url.parse(req.url, true)
  // console.log(urlObj.query.callback)
  res.writeHead(200, {
    'Content-Type': 'application/json; charset=utf-8',
    // CORS 头
    'Access-Control-Allow-Origin': '*'
  })
  switch (urlObj.pathname) {
    case '/api/user':
      // 现在作为客户端 去小米优品 api 请求数据
      // 注意协议要统一:https还是http
      httpPost((data) => {
        res.end(data)
      })
      break
    default:
      res.end('404.')
      break
  }
})
app.listen(3000, () => {
  console.log('localhost:3000')
})
function httpPost(cb) {
  let data = ''
  const options = {
    hostname: 'm.xiaomiyoupin.com',
    port: '443', // 80 是 http 默认端口号,443 是 https 默认端口号
    path: '/mtop/market/search/placeHolder',
    methods: "POST",
    headers: {
      "Content-Type": "application/json",
    }
  }
  const req = https.request(options, (res) => {
    res.on('data', (chunk) => {
      data += chunk
    })
    res.on('end', () => {
      cb(data)
    })
  })
  req.write(JSON.stringify([{}, { baseParam: { ypClient: 1 } }]))
  req.end()
}

1.3 动静分离

动静分离是一种优化技术,将动态生成的内容(如动态网页、API请求)与静态资源(如HTML、CSS、JavaScript、图像文件)分开处理和分发。

  • 静态资源是指:内容长时间不发生改变的资源,例如图片,视频,CSS 文件,JS文件,HTML文件,字体文件等
  • 动态资源是指:内容经常更新的资源,例如百度首页,网易首页,京东搜索列表页面等

HTTP 服务在哪个文件夹中寻找静态资源,那个文件夹就是
静态资源目录,也称之为网站根目录

通过将动态内容和静态资源存储在不同的服务器或服务上,并使用不同的处理机制,可以提高网站的处理效率和响应速度。这种分离的好处包括:

  • 性能优化:将静态资源与动态内容分离可以提高网站的加载速度。可以使用缓存机制将静态资源存储在CDN(内容分发网络)或浏览器缓存中,从而减少网络请求和数据传输的开销。
  • 负载均衡:通过将动态请求分发到不同的服务器或服务上,可以平衡服务器的负载,提高整个系统的可伸缩性和容错性。
  • 安全性:通过将静态资源与动态内容分离,可以更好地管理访问控制和安全策略。

实现动静分离的方法

  • 使用反向代理服务器(如Nginx、Apache)将静态请求和动态请求转发到不同的后端服务器或服务。
  • 将静态资源部署到CDN上,通过CDN分发静态资源,减轻源服务器的负载。
  • 使用专门的静态文件服务器(如Amazon S3、Google Cloud Storage)存储和提供静态资源,而将动态请求交给应用服务器处理。
import fs from 'node:fs'
import http from 'node:http'
import mime from 'mime'
import path from 'node:path'

const server = http.createServer((req, res) => {
    const {method, url} = req
    if (method === 'GET' && url.startsWith('/static')) {
        const staticPath = path.join(process.cwd(), url)
        fs.readFile(staticPath, (err, data) => {
            if (err) {
                res.writeHead(404, {
                    'Content-Type': 'text/plain'
                })
                res.end('not found')
            } else {
                console.log('是兄弟就来缓存我')
                const type = mime.getType(staticPath)
                res.writeHead(200, {
                    // 要求使用 esm 语法,使用 commonjs 会报错
                    'content-type': type, // mime 类型 包含 text/html,text/css 等所有的mime 类型
                    "cache-control": 'public, max-age=3600' // public 缓存任何资源 缓存3600s
                })
                res.end(data)
            }
        })
    }
    // 处理动态资源
    if ((method === 'GET' || method === 'POST') && url.startsWith('/api')) {
        // ...处理动态资源的逻辑
    }
})
server.listen(80, () => {
    console.log('server is running at localhost:80')
})

常见的mime类型:

  • 文本文件:

    • text/plain:纯文本文件
    • text/html:HTML 文件
    • text/css:CSS 样式表文件
    • text/javascript:JavaScript 文件
    • application/json:JSON 数据
  • 图像文件:

    • image/jpeg:JPEG 图像
    • image/png:PNG 图像
    • image/gif:GIF 图像
    • image/svg+xml:SVG 图像
  • 音频文件:

    • audio/mpeg:MPEG 音频
    • audio/wav:WAV 音频
    • audio/midi:MIDI 音频
  • 视频文件:

    • video/mp4:MP4 视频
    • video/mpeg:MPEG 视频
    • video/quicktime:QuickTime 视频
  • 应用程序文件:

    • application/pdf:PDF 文件
    • application/zip:ZIP 压缩文件
    • application/x-www-form-urlencoded:表单提交数据
    • multipart/form-data:多部分表单数据

1.4 邮件服务

常见的用途:

  1. 用户注册和验证:当用户在网站或应用程序上注册时,可以使用邮件服务发送验证链接或验证码给用户,以确保其提供的电子邮件地址有效并与其身份匹配。

  2. 密码重置:当用户忘记密码时,邮件服务可以发送包含密码重置链接的电子邮件给用户,以允许他们设置新密码。

  3. 通知和提醒:邮件服务可以用来向用户发送各种通知和提醒,如订单确认、发货通知、预约提醒、会议邀请等。

  4. 营销和促销活动:企业可以使用邮件服务向客户发送营销和促销信息,如特价促销、新品发布、节日祝福等。

  5. 订阅和邮件列表:邮件服务可以用来处理用户的订阅请求,向订阅者发送定期或即时的更新内容,比如新闻资讯、博客文章等。

前提准备,需要用到 js-yaml(用于解析yaml文件) 和 nodemailer 这两个库。

user.yaml 分别填写自己的邮箱和密码(QQ邮箱这里是授权码)

pass: 'xxx'
user: 'xxx@qq.com'  

QQ 邮箱服务的文档:QQ 邮箱服务

POP3/SMTP 设置方法:

  • 用户名/帐户: 你的QQ邮箱完整的地址
  • 密码: 生成的授权码
  • 电子邮件地址: 你的QQ邮箱的完整邮件地址
  • 接收邮件服务器: pop.qq.com,使用SSL,端口号995
  • 发送邮件服务器: smtp.qq.com,使用SSL,端口号465或587

生成授权码:

在这里插入图片描述

index.js

import nodemailer from 'nodemailer'
import yaml from 'js-yaml'
import http from 'node:http'
import fs from 'node:fs'
import url from "node:url";

const userInfo = yaml.load(fs.readFileSync('./user.yaml', 'utf8'))
// 初始化邮件服务
const transport = nodemailer.createTransport({
    service: 'qq',  // 服务商
    host: 'smtp.qq.com',  //主机
    port: 465,
    secure: true,
    auth: {
        user: userInfo.user,  // 邮箱账号
        pass: userInfo.pass  // 密码 / 授权码
    }
})

http.createServer(async (req, res) => {
    const {method} = req
    const {pathname} = url.parse(req.url)
    if (method === 'POST' && pathname === '/send/mail') {
        let data = ''
        req.on('data', chunk => {
            data += chunk
        })
        req.on('end', () => {
            const {to, subject, text} = JSON.parse(data)
            transport.sendMail({
                to,  // 收件人
                from: userInfo.user,  // 发件人
                subject,  // 主题
                text  // 内容
            })
            res.end('ok')
        })
    }
}).listen(3000, () => {
    console.log('listening on port 3000')
})
POST http://localhost:3000/send/mail HTTP/1.1
Content-Type: application/json

{
  "to": "xxx@qq.com",
  "subject": "标题",
  "text": "我想你了,你还好吗。那天分别之后,你就一句话也没说..."
}

请求成功就可以正常发送邮件了。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小秀_heo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值