Enhance SFTP error handling in SftpController and SftpService by introducing a method to format SftpException messages. Improve listFiles method to handle empty paths and provide clearer error messages in response to exceptions.

This commit is contained in:
liumangmang
2026-02-04 14:43:54 +08:00
parent a1b8a4af8c
commit 7f57d69756
2 changed files with 71 additions and 15 deletions

View File

@@ -1,5 +1,6 @@
package com.sshmanager.controller; package com.sshmanager.controller;
import com.jcraft.jsch.SftpException;
import com.sshmanager.dto.SftpFileInfo; import com.sshmanager.dto.SftpFileInfo;
import com.sshmanager.entity.Connection; import com.sshmanager.entity.Connection;
import com.sshmanager.entity.User; import com.sshmanager.entity.User;
@@ -78,13 +79,28 @@ public class SftpController {
.collect(Collectors.toList()); .collect(Collectors.toList());
return ResponseEntity.ok(dtos); return ResponseEntity.ok(dtos);
} catch (Exception e) { } catch (Exception e) {
log.warn("SFTP list failed: connectionId={}, path={}", connectionId, path, e); String errorMsg = toSftpErrorMessage(e, path, "list");
log.warn("SFTP list failed: connectionId={}, path={}, error={}", connectionId, path, errorMsg, e);
Map<String, String> err = new HashMap<>(); Map<String, String> err = new HashMap<>();
err.put("error", e.getMessage() != null ? e.getMessage() : "List failed"); err.put("error", errorMsg);
return ResponseEntity.status(500).body(err); return ResponseEntity.status(500).body(err);
} }
} }
private String toSftpErrorMessage(Exception e, String path, String operation) {
if (e.getMessage() != null && !e.getMessage().trim().isEmpty()) {
return e.getMessage();
}
Throwable cause = e.getCause();
if (cause instanceof SftpException) {
return SftpService.formatSftpExceptionMessage((SftpException) cause, path, operation);
}
if (e instanceof SftpException) {
return SftpService.formatSftpExceptionMessage((SftpException) e, path, operation);
}
return operation + " failed";
}
@GetMapping("/pwd") @GetMapping("/pwd")
public ResponseEntity<Map<String, String>> pwd( public ResponseEntity<Map<String, String>> pwd(
@RequestParam Long connectionId, @RequestParam Long connectionId,

View File

@@ -3,6 +3,7 @@ package com.sshmanager.service;
import com.jcraft.jsch.ChannelSftp; import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch; import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session; import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpException;
import com.sshmanager.entity.Connection; import com.sshmanager.entity.Connection;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@@ -93,7 +94,9 @@ public class SftpService {
} }
public List<FileInfo> listFiles(SftpSession sftpSession, String path) throws Exception { public List<FileInfo> listFiles(SftpSession sftpSession, String path) throws Exception {
Vector<?> entries = sftpSession.getChannel().ls(path); String listPath = (path == null || path.trim().isEmpty()) ? "." : path.trim();
try {
Vector<?> entries = sftpSession.getChannel().ls(listPath);
List<FileInfo> result = new ArrayList<>(); List<FileInfo> result = new ArrayList<>();
for (Object obj : entries) { for (Object obj : entries) {
ChannelSftp.LsEntry entry = (ChannelSftp.LsEntry) obj; ChannelSftp.LsEntry entry = (ChannelSftp.LsEntry) obj;
@@ -107,6 +110,43 @@ public class SftpService {
)); ));
} }
return result; return result;
} catch (SftpException e) {
String msg = formatSftpExceptionMessage(e, listPath, "list");
throw new RuntimeException(msg, e);
}
}
/**
* Build a user-visible message from JSch SftpException (getMessage() is often null).
*/
public static String formatSftpExceptionMessage(SftpException e, String path, String operation) {
int id = e.getId();
String serverMsg = e.getMessage();
String reason = sftpErrorCodeToMessage(id);
StringBuilder sb = new StringBuilder();
sb.append(reason);
if (path != null && !path.isEmpty()) {
sb.append(": ").append(path);
}
if (serverMsg != null && !serverMsg.trim().isEmpty()) {
sb.append(" (").append(serverMsg).append(")");
} else {
sb.append(" [SFTP status ").append(id).append("]");
}
return sb.toString();
}
private static String sftpErrorCodeToMessage(int id) {
switch (id) {
case 2: return "No such file or directory";
case 3: return "Permission denied";
case 4: return "Operation failed";
case 5: return "Bad message";
case 6: return "No connection";
case 7: return "Connection lost";
case 8: return "Operation not supported";
default: return "SFTP error";
}
} }
public byte[] download(SftpSession sftpSession, String remotePath) throws Exception { public byte[] download(SftpSession sftpSession, String remotePath) throws Exception {