记录一次SFTP文件上传异常

目录

一、异常展示

1.1.日志报错

1.2.nacos中SFTP参数配置

二、bug溯源

2.1.本地代码排查

2.1.1.核心代码展示

2.1.2.补充说明

2.2.本地测试

2.3.服务器测试

2.4.SFTP排查

2.4.1.SFTP访问权限排查

2.4.2.SFTP展示权限排查

三、SFTP配置文件权限说明

四、liunx权限说明


一、异常展示

1.1.日志报错

1.2.nacos中SFTP参数配置

上周客户反应,本地文件生成后,在上传文件时创建SFTP目录时失败,既然有问题,那就找呗,毕竟工作不就是创造bug和解决bug么。由异常报错可知,文件是在上传时,创建SFTP目录时失败,而SFTP的目录是 /1001**********23/,下面记录一下解决问题的思路。

二、bug溯源

2.1.本地代码排查

2.1.1.核心代码展示

java 复制代码
public void upload1(String directory,String name, String sftpFileName, InputStream input) throws SftpException {
		try {
			//创建一级目录
			sftp.cd(directory);
		} catch (SftpException e) {
			logger.warn("directory is not exist:1级目录"+directory);
			//创建多级目录
			createDir(directory,sftp);
			sftp.cd(directory);
		}
		//创建2级目录
		try {
			sftp.cd(directory+name);
		} catch (Exception e) {
			logger.warn("directory is not exist:2级目录"+directory+name);
			sftp.mkdir(directory+name);
			sftp.cd(directory+name);
		}
		
		sftp.put(input, sftpFileName);
		logger.info("file:{} is upload successful", sftpFileName);
	}

	
	/**
	 * 创建一个文件目录
	 */
	public void createDir(String createpath, ChannelSftp sftp) {
		try {
			if (isDirExist(createpath)) {
				this.sftp.cd(createpath);
				return;
			}
			String pathArry[] = createpath.split("/");
			StringBuffer filePath = new StringBuffer("/");
			for (String path : pathArry) {
				if ("".equals(path)) {
					continue;
				}
				filePath.append(path + "/");
				if (isDirExist(filePath.toString())) {
					sftp.cd(filePath.toString());
				} else {
					// 建立目录
					sftp.mkdir(filePath.toString());
					// 进入并设置为当前目录
					sftp.cd(filePath.toString());
				}
			}
			this.sftp.cd(createpath);
		} catch (SftpException e) {
			logger.error("创建路径错误:"+createpath);
		}
	}

	/**
	 * 判断目录是否存在
	 */
	public boolean isDirExist(String directory) {
		boolean isDirExistFlag = false;
		try {
			SftpATTRS sftpATTRS = sftp.lstat(directory);
			isDirExistFlag = true;
			return sftpATTRS.isDir();
		} catch (Exception e) {
			if ("no such file".equals(e.getMessage().toLowerCase())) {
				isDirExistFlag = false;
			}
		}
		return isDirExistFlag;
	}

由客户的日志反馈可知,是upload1方法在创建一级目录时失败,上面是创建一级目录的代码。

2.1.2.补充说明

本地目录创建和SFTP目录创建是不一样的,本地可以一次性创建多级目录,详情请看本地多级目录创建 ,可以直接用mkdirs()方法进行创建多级目录。而SFTP不一样,SFTP没有这个方法,只能用mkdir()方法一级一级创建,具体展示如下:

2.2.本地测试

在排查错误时,除了明显的编写错误以外,别的错误都是不好直接看出来的。所以我们在寻找错误的过程中,Debug是最常用的方法,这里没有上传视频,看图片也差不多的。

截止到这里,符合图片中的日志打印

进一步Debug发现,创建多级目录正常,并无报错。

根据本地 Debug 寻找,发现文件目录正常创建,并没有报错。没报错说明代码的设计是没有问题的,那就需要找系统的问题了。系统方面包含两方面,一方面是本地系统异常,包含白名单和登录失败等问题;一方面是客户SFTP服务器异常,包含创建目录权限限制和SFTP系统配置等。

2.3.服务器测试

这个是用测试服务器和测试SFTP运行的程序,我通过一次性创建5级目录 /1000066666/ICBCRecon/01/02/03/200028029321208/ ,进一步验证了不是代码的问题,同时,我们联系客户,也确认了是①服务器和SFTP之间是不需要添加白名单的,②登录是可以正常登录,③生产环境在访问SFTP时,SFTP的端口也是经过服务器防火墙放行的,这个流程就不做记录了。

2.4.SFTP排查

2.4.1.SFTP访问权限排查

由上述排查可知,程序是可以正常创建多级目录的,那么代码bug的几率就很小了。检查SFTP创建目录的权限。

用nacos 中配置的SFTP用户登录SFTP,并且在 /1001**********23/ 目录的上一层创建 test 目录,发现报的是没有权限。

然后在 /1001**********23/ 目录的下一层创建 test 目录,发现是可以创建的。

由上述操作可知,当用指定用户创建目录时,权限是没问题的。代码没问题,权限没问题,那就要看SFTP配置问题了。

2.4.2.SFTP展示权限排查

从上图可以看到,当前目录是 /data/sftpsite/szfs/1001001001000023/ ,与nacos配置相比,多出来了 /data/sftpsite/szfs/ ,那么就有可能是SFTP目录权限的问题,具体还需要验证。

寻找SFTP的ssh配置文件,文件路径 /etc/ssh/sshd_config ,可以看到:

左边是当前SSH配置文件,文件为初始化配置文件,并没有对目录进行权限限制,右边是应该有的权限配置。

从系统的历史操作可以看到 ,在2023年11月22日,配置文件被修改过,所以系统原有的配置操作被初始化掉了,造成了突然的创建目录异常。

根据配置文件可知,原本添加的权限限制都没了,所以这个时候,nacos 配置的路径就应该是系统全路径,也就是系统绝对路径 ,只配置相对路径是访问不到SFTP目录的,所以才会创建目录失败。

所以解决bug有两种操作,一是将权限添加上,然后系统还访问相对路径;一是不添加权限,系统访问绝对路径。

三、SFTP配置文件权限说明

在一般情况下,用户登录上SFTP以后,看到的目录结构都是相对路径,也就是说是经过限制的路径,而非从系统的根路径开始展示,那么合理的添加限制有哪些作用呢?

在SFTP的配置文件/etc/ssh/sshd_config中添加用户访问权限,可以带来以下几个好处:

  1. 安全性增强:通过设置正确的用户访问权限,可以限制哪些用户可以访问特定的目录或文件,从而提高系统的安全性。
  2. 灵活性增加:可以针对不同的用户或用户组设置不同的访问权限,提供更加灵活的文件访问控制。
  3. 资源管理优化:通过合理的权限设置,可以更好地管理和分配系统资源,避免资源的浪费或过度使用。
  4. 审计和监控:对于有权限访问敏感信息的用户,可以实施更严格的审计和监控措施,确保系统的合规性和安全性。

四、liunx权限说明

我上面在2.4.1进行访问权限排查时,是直接用工具进行目录创建测试,而在Linux中,实际上是不需要创建,只看文件就行,具体操作如下:

在Linux系统中,您可以使用ls -l命令来查看文件操作权限。这个命令会以长格式列出文件和目录的信息,包括权限、所有者、所属组和其他属性。

以下是使用ls -l命令的示例:

java 复制代码
ls -l filename

其中,"filename"是您要查看权限的文件或目录的名称。执行该命令后,将显示类似于以下的结果:

java 复制代码
-rw-r--r-- 1 user group 1234 Oct 23 10:00 filename

您还可以使用 ll 命令来查看文件操作权限,它是ls -l命令的别名。在终端中输入ll命令即可:在这个例子中,文件权限被表示为"-rw-r--r--"。这些字符按照三个一组划分,分别代表所有者、所属组和其他用户的权限。每组的三个字符分别表示读(r)、写(w)和执行(x)权限。如果权限被拒绝,则表示为"-"。

java 复制代码
ll filename

这将以长格式列出文件或目录的详细信息,包括权限、所有者、所属组和其他属性。SFTP查看示例如下:

相关推荐
AI大模型学徒几秒前
Linux(二)_清理空间
linux·运维·服务器
花鱼白羊8 分钟前
TCP Vegas拥塞控制算法——baseRtt 和 minRtt的区别
服务器·网络协议·tcp/ip
守护者17017 分钟前
JAVA学习-练习试用Java实现“使用Arrays.toString方法将数组转换为字符串并打印出来”
java·学习
源码哥_博纳软云19 分钟前
JAVA同城服务场馆门店预约系统支持H5小程序APP源码
java·开发语言·微信小程序·小程序·微信公众平台
禾高网络20 分钟前
租赁小程序成品|租赁系统搭建核心功能
java·人工智能·小程序
学会沉淀。26 分钟前
Docker学习
java·开发语言·学习
如若12327 分钟前
对文件内的文件名生成目录,方便查阅
java·前端·python
PyAIGCMaster29 分钟前
文本模式下成功。ubuntu P104成功。
服务器·数据库·ubuntu
初晴~1 小时前
【Redis分布式锁】高并发场景下秒杀业务的实现思路(集群模式)
java·数据库·redis·分布式·后端·spring·
黑胡子大叔的小屋2 小时前
基于springboot的海洋知识服务平台的设计与实现
java·spring boot·毕业设计