SpringBoot集成FastDFS+Nginx整合基于Token的防盗链的方法

网友投稿 392 2023-01-08


SpringBoot集成FastDFS+Nginx整合基于Token的防盗链的方法

为什么要用SpringBoot?

SpringBoot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。通过这种方式,Spring Boot致力于在蓬勃发展的快速应用开发领域(rapid application development)成为领导者。

创建独立的Spring应用程序

嵌入的Tomcat,无需部署WAR文件

简化Maven配置

自动配置Spring

提供生产就绪型功能,如指标,健康检查和外部配置

绝对没有代码生成并且对XML也没有配置要求

为什么要用Nginx?

概述

Nginx的重要特性

可以针对静态资源高速节点并发访问及缓存。

可以使用反向代理加速,并且可以进行数据缓存。

具有简单负载均衡,节点健康检查和容错功能。

支持远程Fast CGI服务的缓存加速。

支持Fast CGI、Uwsgi、SCGI、Memcached Server的加速和缓存。

支持SSL、TLS、SNI。

具有模块化的架构。

过滤器包括gzip压缩、ranges支持、chunked响应、XSLT、SSL和图像缩放等功能。

在SSL过滤器中,包含多个SSL页面,如果经由Fast CGI或反向代理处理,可以并行处理。

Nginx所具备的WWW服务特性

支持基于域名、端口和IP的虚拟主机配置。

支持KeepAlived和piplined连接。

可进行简单、方便、灵活的配置和管理。

支持修改Nginx配置,并且在代码上线时,可平滑重启,不中断业务访问。

可自定义访问日志格式,临时缓冲写日志操作,快速日志轮询及通过rsyslog处理日志。

可利用信号控制Nginx进程。

支持3xx-5xxHTTP状态码重定向。

支持rewrite模块,支持URI重写及正则表达式匹配。

支持基于客户端IP地址和HTTP基本认证的访问控制。

支持PUT、DELETE、MKCOL、COPY、MOVE等特殊的HTTP请求方法。

支持FLV流和MP4流技术产品应用。

支持HTTP响应速率限制。

支持同一IP地址的并发连接或请求限制。

支持邮件服务代理。

支持高并发,可以支持几百万并发连接。

资源消耗少,在3万并发连接下,可以开启10个nginx的线程消耗的内存不到200MB。

可以做HTTP反向代理及加速缓存,及负载均衡功能,内置对RS节点服务器健康检查功能,折现但能够与专业的HAProxy或LVS的功能。

具备Squid等专业缓存软件等的缓存功能。

支持异步网络I/O事件模型epoll(Linux2.6+)。

Nginx软件主要企业应用

作为Web服务软件。

使用Nginx运行HTML、js、css、小图片等静态数据(类似于Lighttpd)。

结合Fast CGI运行php等动态程序(例如使用fastcgi_pass方式)。

Nginx结合Tomcat/Resin等支持java动态程序(常用proxy_pass)。

反向代理或负载均衡服务(Nginx从1.9.0开始就开始支持TCP的代理了)。

前端业务数据缓存服务。

Web服务应用产品性能对比

静态数据的访问上:处理小文件(小于1MB)时,Nginx和Lighttpd比Apache更有优势,Nginx处理小文件的优势明显,Lighttpd综合最强。

动态数据的访问上:三者差距不大,Apache更有优势,因为处理动态数据的能力在于PHP(Java)和后端数据库的服务能力,也就是说瓶颈不在Web服务器上。

一般情况下普通PHP引擎支持的并发连接参考值3001000。Java引擎和数据库的并发连接参考值3001500。

为什么Nginx比Apache的性能高?

Nginx使用最新版的eepoll(Linux 2.6内核)和kqueue(FreeBSD)异步网络I/O模型,而Apache使用的是传统的select模型。

目前Linux下能够承受高并发访问的Squid、Memcached软件采用都是epoll模型。

处理大量的连接的读写时,Apache所采用的select网络I/O模型比较低。

如何正确采用Web服务器?

静态业务:如果是高并发场景,尽量采用Nginx或Lighttpd,二者首选Nginx。

动态业务:理论上采用Nginx和Apache均可,建议使用Nginx,为了避免相同业务服务的软件多样化,增加维护成本,动态业务可以使用Nginx兼做前端代理,再根据页面的元素或目录转发到其他的服务器进行处理。

既有动态业务又有静态业务,就用Nginx。

关于部署,就不在重复了,如果需要请移步《Java高级架构之FastDFS分布式文件集群》:

使用IDEA场景启动器创建工程

创建Maven工程,修改POM.xml文件添加如下依赖:

org.springframework.boot

spring-boot-autoconfigure

1.5.20.RELEASE

org.springframework.boot

spring-boot-configuration-processor

1.5.20.RELEASE

org.springframework.boot&cgUAQVlt;/groupId>

spring-boot-starter-logging

1.5.20.RELEASE

org.apache.commons

commons-pool2

2.6.0

创建必要的包

annotation:存放相关的注解

autoconfiguation: 存储自动配置类

factory: 存放工厂类

properties: 存放配置参数类

service: 存放服务类

一般情况下,SpringBoot都会提供相应的@EnableXxx注解标注在应用的主启动类上开启某个功能:

// EnableFastdfsClient.java

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

@Import(FastdfsAutoConfiguration.class)

@Documented

public @interface EnableFastdfsClient {

}

下面是相关的自动配置类:

// FastdfsAutoConfiguration.java

@Configuration

@EnableConfigurationProperties(FastdfsProperties.class)

public class FastdfsAutoConfiguration {

@Autowired

private FastdfsProperties fastdfsProperties;

@Bean

@ConditionalOnMissingBean(FastdfsClientService.class)

public FastdfsClientService fastdfsClientService() throws Exception {

return new FastdfsClientService(fastdfsProperties);

}

}

创建相关的工厂类:

// StorageClientFactory.java

// 用于创建连接对象的工厂类

public class StorageClientFactory implements PooledObjectFactory {

@Override

public PooledObject makeObject() throws Exception {

TrackerClient ccgUAQVlient = new TrackerClient();

TrackerServer server = client.getConnection();

return new DefaultPooledObject<>(new StorageClient(server, null));

}

@Override

public void destroyObject(PooledObject p) throws Exception {

p.getObject().getTrackerServer().close();

}

@Override

public boolean validateObject(PooledObject p) {

return false;

}

@Override

public void activateObject(PooledObject p) throws Exception {

}

@Override

public void passivateObject(PooledObject p) throws Exception {

}

}

Properties类用来映射application.properties或者application.yml配置文件:

// FastdfsProperties.java

@ConfigurationProperties(prefix = "fastdfs")

public class FastdfsProperties {

// 连接超时时间

// 网络超时时间

// 字符集编码

// 是否使用Token

// Token加密密钥

// 跟踪器IP地址,多个使用分号隔开

// 连接池的连接对象最大个数

// 连接池的最大空闲对象个数

// 连接池的最小空闲对象个数

// Nginx服务器IP,多个使用分号分割

// 获取连接对象时可忍受的等待时长(毫秒)

private String connectTimeout = "5";

private String networkTimeout = "30";

private String charset = "UTF-8";

private String httpAntiStealToken = "false";

private String httpSecretKey = "";

private String httpTrackerHttpPort = "";

private String trackerServers = "";

private String connectionPoolMaxTotal = "18";

private String connectionPoolMaxIdle = "18";

private String connectionPoolMinIdle = "2";

private String nginxServers = "";

// 需要创建相关的Setter和Getter方法

}

在Service类中封装方法, 下面仅展示3个常用的方法:

// FastdfsClientSerivce.java

public class FastdfsClientService {

// SpringBoot加载的配置文件

// 连接池配置项

// 转换后的配置条目

// 连接池

// Nginx服务器地址

private FastdfsProperties fdfsProp;

private GenericObjectPoolConfig config;

private Properties prop;

private GenericObjectPool pool;

private String[] nginxServers;

private Logger logger;

public FastdfsClientService(FastdfsProperties fdfsProp) throws Exception {

this.fdfsProp = fdfsProp;

this.logger = LoggerFactory.getLogger(getClass());

init();

create();

info();

}

/**

* 初始化全局客户端

*/

private void init() throws Exception {

this.prop = new Properties();

this.logger.info("FastDFS: reading config file...");

this.logger.info("FastDFS: fastdfs.connect_timeout_in_seconds=" + this.fdfsProp.getConnectTimeout());

this.logger.info("FastDFS: fastdfs.network_timeout_in_seconds=" + this.fdfsProp.getNetworkTimeout());

this.logger.info("FastDFS: fastdfs.charset=" + this.fdfsProp.getCharset());

this.logger.info("FastDFS: fastdfs.http_anti_steal_token=" + this.fdfsProp.getHttpAntiStealToken());

this.logger.info("FastDFS: fastdfs.http_secret_key=" + this.fdfsProp.getHttpSecretKey());

this.logger.info("FastDFS: fastdfs.http_tracker_http_port=" + this.fdfsProp.getHttpTrackerHttpPort());

this.logger.info("FastDFS: fastdfs.tracker_servers=" + this.fdfsProp.getTrackerServers());

this.logger.info("FastDFS: fastdfs.connection_pool_max_total=" + this.fdfsProp.getConnectionPoolMaxTotal());

this.logger.info("FastDFS: fastdfs.connection_pool_max_idle=" + this.fdfsProp.getConnectionPoolMaxIdle());

this.logger.info("FastDFS: fastdfs.connection_pool_min_idle=" + this.fdfsProp.getConnectionPoolMinIdle());

this.logger.info("FastDFS: fastdfs.nginx_servers=" + this.fdfsProp.getNginxServers());

this.prop.put("fastdfs.connect_timeout_in_seconds", this.fdfsProp.getConnectTimeout());

this.prop.put("fastdfs.network_timeout_in_seconds", this.fdfsProp.getNetworkTimeout());

this.prop.put("fastdfs.charset", this.fdfsProp.getCharset());

this.prop.put("fastdfs.http_anti_steal_token", this.fdfsProp.getHttpAntiStealToken());

this.prop.put("fastdfs.http_secret_key", this.fdfsProp.getHttpSecretKey());

this.prop.put("fastdfs.http_tracker_http_port", this.fdfsProp.getHttpTrackerHttpPort());

this.prop.put("fastdfs.tracker_servers", this.fdfsProp.getTrackerServers());

ClientGlobal.initByProperties(this.prop);

}

/**

* 显示初始化信息

*/

private void info() {

this.logger.info("FastDFS parameter: ConnectionPoolMaxTotal ==> " + this.pool.getMaxTotal());

this.logger.info("FastDFS parameter: ConnectionPoolMaxIdle ==> " + this.pool.getMaxIdle());

this.logger.info("FastDFS parameter: ConnectionPoolMinIdle ==> " + this.pool.getMinIdle());

this.logger.info("FastDFS parameter: NginxServer ==> " + Arrays.toString(this.nginxServers));

this.logger.info(ClientGlobal.configInfo());

}

/**

* 创建连接池

*/

private void create() {

this.config = new GenericObjectPoolConfig();

this.logger.info("FastDFS Client: Creating connection pool...");

this.config.setMaxTotal(Integer.parseInt(this.fdfsProp.getConnectionPoolMaxTotal()));

this.config.setMaxIdle(Integer.parseInt(this.fdfsProp.getConnectionPoolMaxIdle()));

this.config.setMinIdle(Integer.parseInt(this.fdfsProp.getConnectionPoolMinIdle()));

StorageClientFactory factory = new StorageClientFactory();

this.pool = new GenericObjectPool(factory, this.config);

this.nginxServers = this.fdfsProp.getNginxServers().split(",");

}

/**

* Nginx服务器负载均衡算法

*

* @param servers 服务器地址

* @param address 客户端IP地址

* @return 可用的服务器地址

*/

private String getNginxServer(String[] servers, String address) {

int size = servers.length;

int i = address.hashCode();

int index = abs(i % size);

return servers[index];

}

/**

* 带有防盗链的下载

*

* @param fileGroup 文件组名

* @param remoteFileName 远程文件名称

* @param clientIpAddress 客户端IP地址

* @return 完整的URL地址

*/

public String autoDownloadWithToken(String fileGroup, String remoteFileName, String clientIpAddress) throws Exception {

int ts = (int) (System.currentTimeMillis() / 1000);

String token = ProtoCommon.getToken(remoteFileName, ts, ClientGlobal.getG_secret_key());

String nginx = this.getNginxServer(this.nginxServers, clientIpAddress);

return "http://" + nginx + "/" + fileGroup + "/" + remoteFileName + "?token=" + token + "&ts=" + ts;

}

/**

* 上传文件,适合上传图片

*

* @param buffer 字节数组

* @param ext 扩展名

* @return 文件组名和ID

*/

public String[] autoUpload(byte[] buffer, String ext) throws Exception {

String[] upload = this.upload(buffer, ext, null);

return upload;

}

/**

* 不带防盗链的下载,如果开启防盗链会导致该方法抛出异常

*

* @param fileGroup 文件组名

* @param remoteFileName 远程文件ID

* @param clientIpAddress 客户端IP地址,根据客户端IP来分配Nginx服务器

* @return 完整的URL地址

*/

public String autoDownloadWithoutToken(String fileGroup, String remoteFileName, String clientIpAddress) throws Exception {

if (ClientGlobal.getG_anti_steal_token()) {

this.logger.error("FastDFS Client: You've turned on Token authentication.");

throw new Exception("You've turned on Token authentication.");

}

String nginx = this.getNginxServer(this.nginxServers, clientIpAddress);

return "http://" + nginx + fileGroup + "/" + remoteFileName;

}

// 后面还有好多方法,就不一一展示了

}

为了在IDEA中使用便捷的配置提示功能,我们需要创建元数据文件(resources/spring-configuration-metadata.json):

{

"groups": [

{

"name": "fastdfs",

"type": "com.bluemiaomiao.properties.FastdfsProperties",

"sourceType": "com.bluemiaomiao.properties.FastdfsProperties"

}

],

"properties": [

{

"name": "connectTimeout",

"type": "java.lang.String",

"sourceType": "com.bluemiaomiao.properties.FastdfsProperties",

"defaultValue": "5"

},

{

"name": "networkTimeout",

"type": "java.lang.String",

"sourceType": "com.bluemiaomiao.properties.FastdfsProperties",

"defaultValue": "30"

},

{

"name": "charset",

"type": "java.lang.String",

"defaultValue": "UTF-8"

},

{

"name": "httpAntiStealToken",

"type": "java.lang.String",

"sourceType": "com.bluemiaomiao.properties.FastdfsProperties",

"defaultValue": "false"

}http://,

{

"name": "httpSecretKey",

"type": "java.lang.String",

"sourceType": "com.bluemiaomiao.properties.FastdfsProperties"

},

{

"name": "httpTrackerHttpPort",

"type": "java.lang.Integer",

"sourceType": "com.bluemiaomiao.properties.FastdfsProperties"

},

{

"name": "trackerServers",

"type": "java.lang.String",

"sourceType": "com.bluemiaomiao.properties.FastdfsProperties"

},

{

"name": "connectionPoolMaxTotal",

"type": "java.lang.Integer",

"sourceType": "com.bluemiaomiao.properties.FastdfsProperties",

"defaultValue": "18"

},

{

"name": "connectionPoolMaxIdle",

"type": "java.lang.Integer",

"sourceType": "com.bluemiaomiao.properties.FastdfsProperties",

"defaultValue": "18"

},

{

"name": "connectionPoolMinIdle",

"type": "java.lang.Integer",

"sourceType": "com.bluemiaomiao.properties.FastdfsProperties",

"defaultValue": "2"

},

{

"name": "nginxServers",

"type": "java.lang.String",

"sourceType": "com.bluemiaomiao.properties.FastdfsProperties"

}

],

"hints": [

{

"name": "http_anti_steal_token",

"values": [

{

"value": "false"

},

{

"value": "true"

}

]

}

]

}

应用到项目中

创建SpringBoot项目,勾选Web选项,版本选择1.5.20

进入场景启动器的项目目录执行mvn clean install 将其安装到本地

在POM.xml文件中添加依赖:

com.bluemiaomiao

fastdfs-spring-boot-starter

1.0-SNAPSHOT

记得开启IDEA的自动导入功能

创建配置文件application.properties

fastdfs.nginx-servers=192.168.80.2:8000,192.168.80.3:8000,192.168.80.4:8000

fastdfs.tracker-servers=192.168.80.2:22122,192.168.80.3:22122,192.168.80.4:22122

fastdfs.http-secret-key=2scPwMPctXhbLVOYB0jyuyQzytOofmFCBIYe65n56PPYVWrntxzLIDbPdvDDLJM8QHhKxSGWTcr+9VdG3yptkw

fastdfs.http-anti-steal-token=true

fastdfs.http-tracker-http-port=8080

fastdfs.network-timeout=30

fastdfs.connect-timeout=5

fastdfs.connection-pool-max-idle=18

fastdfs.connection-pool-min-idle=2

fastdfs.connection-pool-max-total=18

fastdfs.charset=UTF-8

或者使用application.yml

fastdfs:

charset: UTF-8

connect-timeout: 5

http-secret-key: 2scPwMPctXhbLVOYB0jyuyQzytOofmFCBIYe65n56PPYVWrntxzLIDbPdvDDLJM8QHhKxSGWTcr+9VdG3yptkw

network-timeout: 30

http-anti-steal-token: true

http-tracker-http-port: 8080

connection-pool-max-idle: 20

connection-pool-max-total: 20

connection-pool-min-idle: 2

nginx-servers: 192.168.80.2:8000,192.168.80.3:8000,192.168.80.4:8000

tracker-servers: 192.168.80.2:22122,192.168.80.3:22122,192.168.80.4:22122

创建控制器类测试方法

// controllers.DownloadController.java

@Controller

@RequestMapping(value = "/download")

public class DownloadController {

@Autowired

private FastdfsClientService service;

@ResponseBody

@RequestMapping(value = "/image")

public String image() throws Exception {

// 之前上传过的数据,实际应用场景应该使用SQL数据库来存储

return service.autoDownloadWithToken("group1", "M00/00/00/wKhQA1ysjSGAPjXbAAVFOL7FJU4.tar.gz", "192.168.80.1");

}

}

项目主页:https://github.com/bluemiaomiao/fastdfs-spring-boot-starter

国内项目主页:https://gitee.com/bluemiaomiao/fastdfs-spring-boot-starter


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:微服务网关有哪些特性(微服务网关技术选型)
下一篇:简单接口自动化框架的实现(java接口自动化框架有哪些)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~