放程序代码的html
这个概念我有点模糊
查了一下RESTful Web 服务 - 介绍
REST是一种软件架构模式前端
HTPP方法 | 做用 |
---|---|
GET | 提供资源的只读访问 |
PUT | 建立一个资源 |
DELETE | 删除一个资源 |
POST | 更新或删除一个资源 |
OPTIONS | 获取资源操做 |
在 REST 架构中,一个 REST 服务器只提供对资源的访问,REST 客户端访问并呈现资源。
说白来就是服务器只负责增删改查,提供资源给前端node
RESTful服务设计。 四个路由(都是HTTP方法)git
在考虑数据库和界面以前, 先设计路由比较好
express文档github
const express = require('express') const app = express() const articles = [ { title: 'example' } ] app.set('port', 3000) /** * 1. 获取全部的文章 */ app.get('/articles', (req, res, next) => { res.send(articles) }) /** * 2. 建立一篇文章 */ app.post('/articles', (req, res, next) => { res.send('OK') }) /** * 3. 获取指定的文章 */ app.get('/articles/:id', (req, res, next) => { const id = req.params.id console.log('fetching:', id) res.send(articles[id]) }) /** * 4. 删除指定的文章 */ app.delete('/articles/:id', (req, res, next) => { const id = req.params.id console.log('fetching:', id) delete articles[id] res.send({ message: 'deleted' }) }) app.listen(app.get('port'), () => { console.log('App started on port', app.get('port')) })
// 好比说 设置了路线GET /user/:name // 那么name属性能够做为req.params.name // GET /user/tj req.params.name // => "tj"
因为chrome浏览器发送delete
方法至关麻烦, 因而我用了一个插件PostMan
,能够模拟各类HTTP请求。很方便web
在上例的代码中, post方法用不了,由于处理post请求须要消息体解析
sql
由于post请求,是给服务器这边发过来数据,发送数据可能有各类格式, 若是本身来写的话会很麻烦,因此导入中间件帮咱们作这件事chrome
了解一下post提交数据的方式数据库
默认表单提交就是这种方式express
通常是上传文件
这种将数据以json格式提交,很赞=。=
没用过,不作评价。
Express没有内置,因而要下载中间件body-parser
(受官方支持)
在上例的基础上加代码
const bodyParser = require('body-parser') app.use(bodyParser.json()) // 1. 支持编码为JSON的请求消息体 app.use(bodyParser.urlencoded({ extended: true })) // 2. 支持编码为表单的请求消息体,也就是默认表单的形式 app.post('/articles', (req, res, next) => { const article = { title: req.body.title, content: req.body.content } articles.push(article) res.send(articles) })
这个中间件会帮咱们把post请求的数据处理好,挂载在req.body
下。
在Node中添加数据库,通常会涉及如下几个步骤
ORM是啥? 百度了一下。
ORM的意思
ORM:(Object/Relation Mapping): 对象/关系映射
ORM就是将编程语言里的对象和数据库中的表创建关系
这里选择使用SQLite, 缘由是由于这个数据库不须要安装,是进程内数据库,开箱即用。
文章应该能被增删改查,模型类Article应该提供如下方法
Demo
const sqlite3 = require('sqlite3').verbose() const dbname = 'later.sqlite' const db = new sqlite3.Database(dbname) db.serialize(() => { const sql = ` CREATE TABLE IF NOT EXISTS articles ( id integer primary key, title, content TEXT ) ` db.run(sql) }) class Article { // cb是callback的缩写 static all(cb) { db.all('SELECT * FROM articles', cb) } static find(id, cb) { db.get('select * from articles where id = ?', id, cb) } static create(data, cb) { const sql = 'insert into articles(title, content) values(?, ?)' db.run(sql, data.title, data.content, cb) } static delete(id, cb) { if (!id) return cb(new Error('pleast provider an id')) db.run('delete from articles where id = ?', id, cb) } } module.exports = db module.exports.Article = Article
关于sql语句, 有些忘了, 查资料SQL语法
还有sqlite的用法 sqliteAPI
对于db.run(sql, [param,...], cb)
执行SQL语句, 不会检索结果。 若是执行失败了,就会调用回调函数。
执行SQL查询, 将第一个结果回调, 注意回调有两个参数, 第一个是error, 第二个才是结果
执行SQL查询, 将全部的结果回调
下了一款sqlite的工具,往表里插了几条数据,测试了一下都是正确的~~
将db.js导入以前写的路由中
const express = require('express') const app = express() const Article = require('./db').Article const bodyParser = require('body-parser') app.set('port', 3000) app.use(bodyParser.json()) // 1. 支持编码为JSON的请求消息体 app.use(bodyParser.urlencoded({ extended: true })) // 2. 支持编码为表单的请求消息体 /** * 获取全部的文章 */ app.get('/articles', (req, res, next) => { Article.all((err, articles) => { if (err) return next(err) res.send(articles) }) }) /** * 建立一篇文章 */ app.post('/articles', (req, res, next) => { const article = { title: req.body.title, content: req.body.content } Article.create(article, (err) => { return next(err) }) res.send('create OK') }) /** * 获取指定的文章 */ app.get('/articles/:id', (req, res, next) => { const id = req.params.id Article.find(id, (err, article) => { if(err) return next(err) res.send(article) }) }) /** * 删除指定的文章 */ app.delete('/articles/:id', (req, res, next) => { const id = req.params.id Article.delete(id, (err) => { return next(err) }) res.send({ message: 'deleted' }) }) app.listen(app.get('port'), () => { console.log('App started on port', app.get('port')) })
增删改查的功能的实现好了
文章确定咱们不想一个一个慢慢建立,咱们能够用readability
之类的模块,自动帮咱们从网页中提取文章
这里书上用了readability
yarn add node-readability
const read = require('node-readability') app.post('/download/articles', (req, res, next) => { const url = req.body.url read(url, (err, result) => { if (err || !result) { res.status(500).send('Errror downloading article') } const article = { title: result.title, content: result.content } Article.create(article, (err) => { return next(err) }) res.send('create OK') }) })
使用这个库里的read()方法, 传入须要爬取的文章地址。
在回调函数中能获取能该网页
const article = { title: result.title, content: result.content // 这个获得的是内容的html }
拿到html后, 咱们能够经过模板引擎来渲染用户界面。
结合Express和EJS
首先建立模板文件,
<html> <head> <title>Later</title> </head> <body> <div class="container"> <ul> <% articles.forEach((article) => { %> <li> <a href="/articles/<%= article.id %>"> <%= article.title %> </a> <div> <%- article.content %> </div> </li> <% }) %> </ul> </div> </body> </html>
注意点
<%= code %>会对code进行html转义
<%- code %>将不会进行转义
通常咱们在用浏览器输入地址http://localhost:3000/articles
后
浏览器发出get请求, 通常请求类型都是text/html
Express提供的 res.format 方法,它能够根据请求发送响应格式的响应。
因而写代码
app.get('/articles', (req, res, next) => { Article.all((err, articles) => { if (err) return next(err) res.format({ html: () => { res.render('articles.ejs', { articles }) // 会自动去views/articles.ejs查找 }, json: () => { res.send(articles) } }) }) })
使用express能够很快的搭出应用,可是在其中咱们须要用挺多中间件的
像这个项目就用到了三个
"body-parser": "^1.18.3", "ejs": "^2.6.1", "node-readability": "^3.0.0",
body-parser 在客户端post请求给服务器发送数据的时候, 这个中间件能够替咱们解析各类请求方式的数据。简化操做
ejs 是模板引擎,用于渲染
node-readability 是用来下载文章的,随便给它一个网页,它能解析出文章内容,有点相似爬虫
这算是一个MVC的小项目了使用express做为控制器(Controller)这一层, 负责转发请求,处理请求使用ejs做为视图层(Views)渲染页面使用sqlite做为模型层(Model)数据库存储数据