Restful 表述性状态传递

Restful

REST表述性状态传递

REST通常基于使用HTTP,URL,XML,HTML。

REST使用的数据格式为JSON

HTTP方法

GET 获取数据

PUT 用于更新和添加数据

DELETE 用于删除数据

POST 添加数据

RESTful

一种基于http的架构方式

资源与URL

REStful全称为表述性状态转移。任何事物只要有被引用的必要都为资源。资源可以为实体,可以为抽象的概念。

资源举例

用户的手机号

用户的个人信息

用户手机潜在的价值

资源要被识别,要有唯一的标识。

URL可以看成资源的地址,可以看成资源的名称。

以github举例

仓库地址 https://github.com/mySoul8012/code

个人信息地址 https://github.com/mySoul8012

看URL可知仓库是在那个用户名下的

一些设计技巧

使用-或者_来进行资源的分割

使用/来表示资源的层级关系

使用?将资源进行过滤 /pulls?state=closed 表示已经关闭的推送请求,URL对应的是一种特定的查询结果。

.或者:表示同级的资源关系

统一的资源接口

幂等

指一次或者多次请求一个资源的时候,应该具有相同的副作用。属于语义化的一个词

HTTP协议是一种面向资源的应用层协议

GET用于获取资源,不应该有副作用,所以称为其幂等性,例如请求一个资源的时候,不会改变其状态,此时说明GET具有幂等性

HTTP的DELETE,会删除资源,此时具有副作用,但是多次的副作用是相同的,还是具有其幂等性

POST为创建一个资源,每次副作用都是不同的,即没有幂等性

PUT为更新资源,对于同一个URL一次和多次的是相同的,此时具有幂等性

GET

安全且幂等,表示一种获取的表示,会有缓存

POST

不安全且不幂等,使用服务器端的管理的实例号生成资源,创建子资源,用于部分更新资源,如果没有修改则不会更新资源(一种乐观锁的表示)

PUT

PUT不安全且幂等。用客户端管理的实例,创建一个资源,通过替换的方式更新资源

DELETE

不安全但是幂等

四种总结

四种tcp方式,都是不安全,因为都是明文传输,需要使用https,完成加密,防止被抓包

一些问题

一个框架 rails

官方网站 https://rubyonrails.org/

或者名为 Ruby on Rails

一种基于Ruby语言即面向对象,命令式,函数式,动态的通用编程语言,由日本科学家发明。特点是函数式编程

这是一个开源的web应用框架,严格按照MVC架构开发。

应用

Github

推特

basecamp

Groupon

yellowpages

POST和PUT

为博客增加一个Java分类,生成的路径名为/categories/java 采用PUT方法,完成更新,因为此时是由客户端决定的

客户端不一定支持HTTP方法

rails 框架是通过隐藏参数的方法,达到传递真实请求的方式

资源的表述

客户端获取的只是资源的表述。即资源的外在表现。

资源的表述包括数据和描述数据的元数据。

通过HTTP内容的协商,客户端通过头部信息达到

以github为例,JSON表述如下

undefined

一些常见的表述

URL里带上版本号

URL后缀区分表述格式

处理不支持的表述格式

undefined

资源的链接

超链接即状态引擎。

在表述格式里加入连接引导客户端。即这种链接称为流通性

以github为例

undefined

状态的转移

应用状态和资源状态

状态应该区分应用状态和资源状态。

客户端维护应用状态。

服务端维护资源状态。

客户端和服务端交互必须是无状态的。

Cookie是保存一些服务器不依赖于会话状态即可依赖的信息。

应用状态的转移

会话状态不是作为资源状态保存在服务器端的,而是被客户端作为应用状态进行跟踪的。客户端的应用在服务器端指引的超链接指引下发生变迁。

为一种架构模式

创建RESTful

创建一个JSON数据资源文件

{
	"user1": {
		"name": "mahesh",
		"password": "password",
		"profession": "teacher",
		"id": 1
	},
	"user2": {
		"name": "suresh",
		"password": "password2",
		"profession": "libraian",
		"id": 2
	},
	"user3": {
		"name": "ramesh",
		"password": "password3",
		"profession": "clerk",
		"id": 3
	},
}

即根据JSON文件有以下api

序号

Url

Http方法

发送内容

结果

1

listUsers

GET

显示所有用户列表

2

addUser

POST

JSON字符串

添加新用户

3

deleteUsers

DELETE

JSON字符串

删除用户

4

id

GET

显示用户详细信息

获取用户列表

http://127.0.0.1:1937/listUsers
/*server.js*/
var express = require('express');	// 引入express框架
var app = express();
var fs = require('fs');	 // 引入文件模块

// 创建get请求
app.get('/listUsers', (req, res) => {
	fs.readFile(__dirname + '/' + 'users.json', 'utf8', (err, data) => {	// 读取文件
		console.log( data );
		res.end(data);	// 将读取到的内容返回给客户端
	});
});

// 启动server
var server = app.listen(1937, () => {
	console.log(server.address());
})

查看一下JSON数据

undefined

这样暂时完成了一部分

添加用户

JSON.parse有个小坑,最后不允许使用,作为结尾

/*server.js*/
var express = require('express');	// 引入express框架
var app = express();
var fs = require('fs');	 // 引入文件模块

// 添加用户的数据
var user = {
	"user4": {
		"name":"mohit",
		"password":"password4",
		"profession":"teacher",
		"id":4
	}
}

// 创建get请求
app.get('/addUser', (req, res) => {
	// 读取已存在的数据
	fs.readFile( __dirname + "/" + "users.json", "utf8", (err, data) => {
		if (err) {
			return console.log(err);
		};

		data = JSON.parse(data);	// 将传入的JSON转换为对象格式
		data["user4"] = user["user4"];	
		console.log(data);
		res.end( JSON.stringify(data) );	// 将对象转换成为JSON格式
	});
});

// 启动server
var server = app.listen(1937, () => {
	console.log(server.address());
})
{
	"user1": {
		"name": "mahesh",
		"password": "password",
		"profession": "teacher",
		"id": 1
	},
	"user2": {
		"name": "suresh",
		"password": "password2",
		"profession": "libraian",
		"id": 2
	},
	"user3": {
		"name": "ramesh",
		"password": "password3",
		"profession": "clerk",
		"id": 3
	}
}

访问 http://127.0.0.1:1937/addUser

返回的JSON数据

undefined

此时本地的JSON数据仍旧未发生改变,如果要其发生改变需要fs的写模块,将JSON数据写入JSON文件中

显示用户详情

/*server.js*/
var express = require('express');	// 引入express框架
var app = express();
var fs = require('fs');	 // 引入文件模块

// 添加用户的数据
var user = {
	"user4": {
		"name":"mohit",
		"password":"password4",
		"profession":"teacher",
		"id":4
	}
}

// 创建获取用户列表路由
app.get('/listUsers', function (req, res) {
   fs.readFile( __dirname + "/" + "users.json", 'utf8', function (err, data) {
       console.log( data );
       res.end( data );
   });
})

// 创建添加用户路由请求
app.get('/addUser', (req, res) => {
	// 读取已存在的数据
	fs.readFile( __dirname + "/" + "users.json", "utf8", (err, data) => {
		if (err) {
			return console.log(err);
		};

		data = JSON.parse(data);	// 将传入的JSON转换为对象格式
		data["user4"] = user["user4"];	
		console.log(data);
		res.end( JSON.stringify(data) );	// 将对象转换成为JSON格式
	});
});

// 添加显示用户详情路由
app.get('/:id', (req, res) => {
	// 首先读取已存在的用户
	fs.readFile( __dirname + '/' + "users.json", 'utf8', (err, data) => {
		data = JSON.parse( data );
		var user = data["user" + req.params.id]	// 获取get得到的值
		console.log( user );
		res.end( JSON.stringify(user) );
	})
})

// 启动server
var server = app.listen(1937, () => {
	console.log(server.address());
})

查看浏览器得到的JSON数据

undefined

删除用户

/*server.js*/
var express = require('express');	// 引入express框架
var app = express();
var fs = require('fs');	 // 引入文件模块


// 创建获取用户列表路由
app.get('/listUsers', (req, res) => {
   fs.readFile( __dirname + "/" + "users.json", 'utf8', (err, data) => {
       console.log( data );
       res.end( data );
   });
})

// 创建添加用户路由请求
app.get('/addUser', (req, res) => {
	// 读取已存在的数据
	fs.readFile( __dirname + "/" + "users.json", "utf8", (err, data) => {
		if (err) {
			return console.log(err);
		};

		// 添加用户
		var user = {
		"user4": {
		"name":"mohit",
		"password":"password4",
		"profession":"teacher",
		"id":4
				}
		}

		data = JSON.parse(data);	// 将传入的JSON转换为对象格式
		data["user4"] = user["user4"];	
		console.log(data);
		res.end( JSON.stringify(data) );	// 将对象转换成为JSON格式
	});
});

// 添加显示用户详情路由
app.get('/:id', (req, res) => {
	// 首先读取已存在的用户
	fs.readFile( __dirname + '/' + "users.json", 'utf8', (err, data) => {
		data = JSON.parse( data );
		var user = data["user" + req.params.id]	// 获取get得到的值
		console.log( user );
		res.end( JSON.stringify(user) );
	})
})

var app = express();	// 不清楚为什么这里要重新定义?
// 删除用户
app.get('/deleteUser', (req, res) => {

   // 首先获取用户信息
   fs.readFile( __dirname + "/" + "users.json", 'utf8', (err, data) => {
       data = JSON.parse( data );
       delete data["user" + 2];
       
       console.log( data );
       res.end( JSON.stringify(data));
   });
})

// 启动server
var server = app.listen(1937, () => {
	console.log(server.address());
})

不清楚为什么要重新定义一个类。

undefined

undefined

undefined

undefined

undefined

undefined

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏向治洪

Rest api简介

理解和使用内容协商 我们的开发者在发送一个 REST API 请求的同时,根据应用场景,针对相同的资源,可能会期待不同的返回形式。 比如,我希望根据用户客户端语...

27760
来自专栏惨绿少年

练习题三

第1章 练习题 1.1 第1题 取得/etc/hosts 文件的权限 如何取得/etc/hosts 文件的权限对应的数字内容,如-rw-r--r--  为 64...

23400
来自专栏编程

《PHP扩展及核心》

一、主要内容: 1⃣php扩展的概念和底层实现 2⃣编写一个php扩展的步骤 3⃣php底层,Zend 引擎API的介绍 ,HashTable 原理 二、相关概...

25680
来自专栏飞雪无情的博客

Go语言实战笔记(十二)| Go goroutine

一般的程序,如果没有特别的要求的话,是顺序执行的,这样的程序也容易编写维护。但是随着科技的发展、业务的演进,我们不得不变写可以并行的程序,因为这样有很多好处。

12930
来自专栏运维小白

10.23 linux任务计划cron

Linux任务计划 crontab -u、-e、-l、-r 格式:分 时 日 月 周 user command 文件/var/spool/cron/userna...

20990
来自专栏WindCoder

《Linux内核分析》之触发一个系统调用实验总结

系统调用列表中可用的很多,可惜对用代码进行系统调用不太清楚,只好从网上窃取了一份,地址在最后放上。此处以fork()为例。

11630
来自专栏从零开始学自动化测试

pytest文档22-pytest分布式执行(pytest-xdist)

平常我们手工测试用例非常多时,比如有1千条用例,假设每个用例执行需要1分钟。如果一个测试人员执行需要1000分钟才能执行完,当项目非常紧急的时候, 我们会用测试...

46340
来自专栏黑白安全

PHP安全编码规范之安全配置篇

因为配置不当引发的安全问题是屡见不鲜的,通过一系列的安全配置,可以很好的解决一些安全隐患,从而为系统增加安全系数。但是在开发过程中,因为需求的改变和编程的习惯可...

31520
来自专栏信安之路

web应用渗透测试流程

对于web应用的渗透测试,一般分为三个阶段:信息收集、漏洞发现以及漏洞利用。下面我们就分别谈谈每个阶段需要做的事情。

16600
来自专栏枕边书

用Lua定制Redis命令

前言 Redis作为一个非常成功的数据库,提供了非常丰富的数据类型和命令,使用这些,我们可以轻易而高效地完成很多缓存操作,可是总有一些比较特殊的问题或需求需要解...

51170

扫码关注云+社区

领取腾讯云代金券