图片服务器项目浅析

本文介绍了一个图片服务器项目的实现,包括核心功能如图片上传、获取、删除,数据库设计和HTTP API设计。通过RESTful风格,使用MySQL存储图片信息,并提供Postman测试指导和后续扩展思考。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、项目背景

类似于在csdn中上传图片一样,我们选择了图片上传后,会进入选择图片文件的界面,然后上传成功后,我们就可以看到上传的图片被展示出来,其实我们是将图片上传到了csdn的后台服务器中,而我们要实现的就是具备这样功能的一个图片服务器,可以提供对图片的增删查改操作。

2、核心功能

 

该项目的核心就是实现一个HTTP服务器,然后用这个服务器来存储图片,针对每一个图片提供一个唯一的url,有了这个url之后,就可以借助它把图片展示到其它网页上。具体需求包括:

  • 上传图片(得到一个url)
  • 根据图片的url访问图片,获取图片内容
  • 获取某个图片的属性
  • 删除图片

3、模块划分

  1. 数据库存储模块

 包括:设计数据库、使用MySQL C API操作数据库

     2. 服务器模块

  包括:新增图片、查看所有图片元信息、查看指定图片元信息、查看图片内容、删除图片

4、数据库设计

create database if not exists image_system;
use image_system;

创建图片表

drop table if exists `image_table`
create table `image_table`(image_id int not null primary key auto_increment,
                          image_name varchar(50), 
                          size bigint, 
                          upload_time varchar(50),
                          md5 varchar(128),
                          content_type varchar(50) comment '图片类型', 
                          path varchar(1024) comment '图片所在路径')

其中, image_id为主键自增属性。

什么是md5?

这是一种常见字符串hash算法,具有三个特性:

  1. 不管源字符串多长,得到的最终md5值都是固定长度
  2. 源字符串稍微变化一点点内容,md5值会变化很大(降低冲突概率)
  3. 通过源字符串很容易计算得到md5值,但根据md5推导出原字符串很难(几乎不可能)

md5的作用:用来校验图片内容正确性。

上传图片的时候,服务器就可以计算一个该图片的md5值,后续用户下载图片的时候,也能获取到该图片的md5,用户可以把自己计算的md5和服务器计算的md5进行对比,以此判断下载的图片是否正确。

使用MySQL C API操作数据库

安装MySQL C API

yum install mysql -devel

代码中使用时需要链接上MySQL提供的库

-L /usr/lib64/mysql -lmysqlclient 

5、服务器API设计

我们需要实现一个HTTP服务器,HTTP服务器需要接受http请求,返回http响应,此处需要约定不同的请求来表示不同的操作方式,例如:有些请求表示上传图片,有些请求表示查看图片,有些表示删除图片。

此处我们使用Restful风格的设计。

  1. http method来表示操作的动词:GET查,POST增,PUT改,DELETE删
  2. http path表示操作的对象
  3. 补充信息一般使用body来传递,通常情况下body中使用json格式的数据来组织
  4. 响应数据通常也是用json格式组织

json是一种数据组织格式,最主要的用途之一就是序列化。json源于javascript,用来表示一个对象,类似于map采用key:value的格式。

json优势:方便调试

json劣势:组织格式的效率比较低,更占存储空间和带宽

具体设计:

1、上传图片

请求:
POST /image
Content-Type: application/x-www-form-urlencoded

------WebKitFormBoundary5muoelvEmAAVUyQB
Content-Disposition: form-data; name="filename"; filename="图标.jpg"
Content-Type: image/jpeg
......[图片正文].....

响应:
HTTP/1.1 200 OK
{
    "ok": true,
}

2、查看所有图片元信息

请求:
GET /image/

HTTP/1.1 200 OK
[
    {
        "image_id": 1,
        "image_name": "1.png",
        "content_type": "image/png",
        "md5": "[md5值]"
    }
]

3、查看指定图片元信息

请求:   
GET /image/:image_id 
 
响应: 
HTTP/1.1 200 OK 

    "image_id": 1, 
    "image_name": "1.png", 
    "content_type": "image/png", 
    "md5": "[md5值]" 

4、查看指定图片内容

请求: 
GET /image/show/:image_id 
 
响应:   
HTTP/1.1 200 OK 
content-type: image/png 
 
[响应 body 中为 图片内容 数据]

5、删除图片

请求:   
DELETE /image/:image_id 
 
响应: 
HTTP/1.1 200 OK 

    "ok": true 

 6、服务端设计

封装数据库操作

db.hpp

namespace image_system { 
    static MYSQL* MySQLInit() {} 
    static void MySQLRelease(MYSQL* mysql) {} 
     
class ImageTable { 
    ImageTable(MYSQL* mysql) {  } 
    bool Insert(const Json::Value& image); 
    bool SelectAll(Json::Value* images); 
    bool SelectOne(int32_t image_id, Json::Value* image); 
    bool Delete(int image_id); 
}; 
} 

具体的各个接口代码实现此处不全部展示了。其中包括新增、查询所以、查询指定图片及删除的接口代码。完成后写一段测试代码测试各个接口的功能是否满足预期。

服务器基本框架

使用cpp-httplib.h

#include "httplib.h" 
 
int main() { 
  using namespace httplib; 
  Server server; 
  server.Get("/", [](const Request& req, Response& resp) { 
    (void)req; 
    resp.set_content("<html>hello</html>", "text/html"); 
  });   
  server.set_base_dir("./wwwroot"); 
  server.listen("0.0.0.0", 9094); 
  return 0; 
} 

构建HTTP服务器提供约定的API接口

#include <signal.h> 
#include <jsoncpp/json/json.h> 
#include "util.hpp" 
#include "db.hpp" 
#include "httplib.h" 
#include <openssl/md5.h> 
 
std::string StringMD5(const std::string& str); 
 
const std::string base_path = "./image_data/"; 
 
MYSQL* mysql = NULL; 
 
int main() { 
  using namespace httplib;  
  using namespace image_system; 
  Server server; 
   
  // 1. 数据库客户端初始化和释放 
  mysql = MySQLInit(); 
  signal(SIGINT, [](int) { MySQLRelease(mysql); exit(0);}); 
  ImageTable image_table(mysql); 
 
  // 2. 先按照 cpp-httplib 的文档演示基本的图片上传处理过程 
  server.Post("/image_test", [](const Request& req, Response& resp) { 
     
  }); 
 
  // 3. 新增图片. 
  server.Post("/image", [&image_table](const Request& req, Response& resp) { 
     
  }); 
 
  // 4. 查看所有图片的元信息 
  server.Get("/image", [&image_table](const Request& req, Response& resp) { 
  
  }); 
   
 
  // 5. 查看图片元信息 
  // raw string(c++ 11), 转义字符不生效. 用来表示正则表达式正好合适 
  // 关于正则表达式, 只介绍最基础概念即可. \d+ 表示匹配一个数字 
  // http://help.locoy.com/Document/Learn_Regex_For_30_Minutes.htm 
  server.Get(R"(/image/(\d+))", [&image_table](const Request& req, Response& resp) { 
 
  }); 
 
  // 6. 查看图片内容 
  server.Get(R"(/image/show/(\d+))", [&image_table](const Request& req, Response& resp) { 
 
  }); 
 
  // 设置静态文件目录 
  server.set_base_dir("./wwwroot"); 
 
  server.listen("0.0.0.0", 9094); 
  return 0; 
} 
 
// 需要包含头文件  
// #include <openssl/md5.h> 
// Makefile 需要 -lcrypto 
std::string StringMD5(const std::string& str) { 
  const int MD5LENTH = 16; 
  unsigned char MD5result[MD5LENTH]; 
  // 调用 openssl 的函数计算 md5 
  MD5((const unsigned char*)str.c_str(),str.size(),MD5result); 
  // 转换成字符串的形式方便存储和观察 
  char output[1024] = {0}; 
  int offset = 0; 
  for (int i = 0; i < MD5LENTH; ++i) { 
    offset += sprintf(output + offset, "%x", MD5result[i]); 
  } 
  return std::string(output); 
} 

测试上传图片,实现一个测试页面upload.html,生成一个按钮,点击之后弹出文件选择框,发送按钮,就会给服务器发送一个特殊的http请求。验证上传的图片是否能成功。

<html> 
<head> 
  <meta http-equiv="Content-Type" content="text/html;charset=utf-8"> 
</head> 
<body>
    <form method="POST" enctype="multipart/form-data" 
action="http://47.98.116.42:9094/image"> 
        <table> 
            <tr> 
                <td>文件上传:</td> 
                <td><input type="file" name="filename"/></td> 
            </tr> 
            <tr> 
                <td></td> 
                <td><input type="submit" value="上传"/></td> 
            </tr> 
        </table> 
    </form> 
</body> 
</html> 

完整的上传图片接口、查看所有图片元信息、查看单个图片元信息接口、查看图片内容接口以及删除图片接口的实现代码详见github中。

正则表达式简单了解及使用

raw string(C++ 11),作用是使转义字符不生效,用来表示正则表达式正好合适

正则表达式是一个带有特殊符号的字符串,描述了一个字符串的特征。(字符串应该包含什么信息,某个信息开头,以某个信息结尾,某个信息重复出现多少次等),代码中使用的\d+ 表示匹配一个数字。

7、使用Postman进行测试

http客户端,可以很方便的构造http请求并进行测试。

8、后续扩展点

  1. 存储时合并文件,上传大量的比较小的文件,把这些逻辑上比较小的文件合并成一个比较大的物理文件,数据库里面除了存这个该文件的路径之外,再存一个偏移量,方便这些小文件的查找。
  2. 防盗链,其实就是一个权限控制。只让图片能被特定的用户使用。借助cookie,实现相关用户账户验证功能。
  3. 支持一些简单图片处理功能,例如:请求中带上参数w=50&h=50,得到一个50*50的图片。
  4. 对内容相同的图片只存一份图片文件。可以通过md5来判定这两个图片是否相同,然后通过引用计数实现同一个图片只存一份。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值