您现在的位置是:主页 > news > 海拉尔网站建设 网站设计/举一个病毒营销的例子
海拉尔网站建设 网站设计/举一个病毒营销的例子
admin2025/5/27 12:16:00【news】
简介海拉尔网站建设 网站设计,举一个病毒营销的例子,国外很炫酷的网站,长沙网站建设王道下拉棒在华为云上部署系统后FTP上传失败的解决过程记录1、问题描述2、问题分析3、配置FTP服务器为被动模式4、在华为云控制台设置安全组及防火墙结束1、问题描述 有许多功能用到了图片上传,系统采用浏览器http上传到应用服务器,应用服务器再上传到独立的ftp服…
在华为云上部署系统后FTP上传失败的解决过程记录
- 1、问题描述
- 2、问题分析
- 3、配置FTP服务器为被动模式
- 4、在华为云控制台设置安全组及防火墙
- 结束
1、问题描述
有许多功能用到了图片上传,系统采用浏览器http上传到应用服务器,应用服务器再上传到独立的ftp服务器,方便图片资源的统一管理。在开发阶段测试没有任何问题,但是部署到华为云服务器后总是提示上传失败。系统部署图如下:
其中应用服务器上部署了3个服务一个ui站点,ui站点上就有文件上传的界面操作,实际调用文件上传的功能在Admin rest服务上。
关键代码如下:
package io.platform.base.common.utils;import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.SocketException;
import java.util.regex.Pattern;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPClientConfig;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;/*** Created by chen on 2017/12/27.*/
@Component
public class FtpUtils {@Value("${ftp.passiveModeEnabled}")private boolean passiveModeEnabled; //是否启用被动模式@Value("${ftp.userName}")private String userName; //登录名@Value("${ftp.password}")private String password; //密码@Value("${ftp.ftpHostName}")private String ftpHostName; //ftp地址@Value("${ftp.port}")private int port; //端口private FTPClient ftpClient = new FTPClient();private OutputStream os = null;private InputStream is = null;private Logger logger = LoggerFactory.getLogger(getClass());private Pattern pattern = Pattern.compile("\\d{8}"); //8位数字/*** 建立链接*/private void connect() {try {logger.info("开始链接...");ftpClient.connect(ftpHostName, port);int reply = ftpClient.getReplyCode(); //ftp响应码if (!FTPReply.isPositiveCompletion(reply)) { //ftp拒绝链接logger.error("ftp拒绝链接...");ftpClient.disconnect();}ftpClient.login(userName, password);if (this.passiveModeEnabled) {ftpClient.enterLocalPassiveMode(); //设置被动模式 通知server端开通端口传输数据}ftpClient.setBufferSize(256);ftpClient.setFileType(FTP.BINARY_FILE_TYPE);ftpClient.setControlEncoding("utf-8");logger.info("登录成功!");} catch (SocketException e) {// TODO Auto-generated catch blocklogger.error(e.getMessage(), e);} catch (IOException e) {// TODO Auto-generated catch blocklogger.error(e.getMessage(), e);}}/*** 退出FTP登录关闭链接 并 关闭输入输出流** @param*/private void close() {try {if (is != null) {is.close();}if (os != null) {os.flush();os.close();}ftpClient.logout();logger.info("退出登录!");ftpClient.disconnect();logger.info("关闭链接!");} catch (IOException e) {// TODO Auto-generated catch blocklogger.error(e.getMessage(), e);}}/*** 判断是否是目录** @param fileName* @return*/public boolean isDir(String fileName) {try {// 切换目录,若当前是目录则返回true,否则返回true。boolean falg = ftpClient.changeWorkingDirectory(fileName);return falg;} catch (IOException e) {// TODO Auto-generated catch blocklogger.error(e.getMessage(), e);}return false;}/*** 上传文件** @param ftpPath* @param fileName*/public boolean uploadFile(String ftpPath, String fileName, InputStream is) {connect();boolean flag = uploadFileByDo(ftpPath, fileName, is);close();return flag;}/*** 下载文件** @param remoteFtpPath* @param localPath* @param fileName* @return*/public boolean downloadFile(String remoteFtpPath, String localPath, String fileName) {connect();boolean flag = this.downloadFileByDo(remoteFtpPath, localPath, fileName);close();return flag;}/*** 删除ftp上的文件** @param ftpFileName* @return true || false*/public boolean removeFile(String ftpFileName) {boolean flag = false;logger.info("待删除文件:{0}", ftpFileName);try {ftpFileName = new String(ftpFileName.getBytes("GBK"), "iso-8859-1");flag = ftpClient.deleteFile(ftpFileName);logger.info("删除文件:[{0}]", flag ? "成功" : "失败");return flag;} catch (IOException e) {e.printStackTrace();return false;}}/*** 删除空目录** @param dir* @return*/public boolean removeDir(String dir) {if (StringUtils.startsWith(dir, "/"))dir = "/" + dir;try {String d = new String(dir.toString().getBytes("GBK"), "iso-8859-1");return ftpClient.removeDirectory(d);} catch (Exception e) {e.printStackTrace();return false;}}/*** 创建目录(有则切换目录,没有则创建目录)** @param dir* @return*/public boolean createDir(String dir) {if (StringUtils.isBlank(dir))return true;String d;try {//目录编码,解决中文路径问题d = new String(dir.toString().getBytes("GBK"), "iso-8859-1");//尝试切入目录if (ftpClient.changeWorkingDirectory(d))return true;String[] arr = dir.split("/");StringBuffer sbfDir = new StringBuffer();//循环生成子目录for (String s : arr) {sbfDir.append("/");sbfDir.append(s);//目录编码,解决中文路径问题d = new String(sbfDir.toString().getBytes("GBK"), "iso-8859-1");//尝试切入目录if (ftpClient.changeWorkingDirectory(d))continue;if (!ftpClient.makeDirectory(d)) {logger.info("[失败]ftp创建目录:" + sbfDir.toString());return false;}logger.info("[成功]创建ftp目录:" + sbfDir.toString());}//将目录切换至指定路径return ftpClient.changeWorkingDirectory(d);} catch (Exception e) {e.printStackTrace();return false;}}/*** 上传文件** @param ftpPath FTP服务器保存目录* @param fileName 上传到FTP服务器上的文件名*/private boolean uploadFileByDo(String ftpPath, String fileName, InputStream is) {try {if (!createDir(ftpPath)) {throw new RuntimeException("切入FTP目录失败:" + ftpPath);}ftpClient.setBufferSize(1024);//解决上传中文 txt 文件乱码ftpClient.setControlEncoding("utf-8");FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_NT);conf.setServerLanguageCode("zh");// 设置文件类型(二进制)ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);if (ftpClient.storeFile(fileName, is)) {is.close();return true;} else {logger.info("上传文件失败!");return false;}} catch (IOException e) {// TODO Auto-generated catch blocklogger.error(e.getMessage(), e);return false;} finally {try {if (is != null) {is.close();}} catch (IOException e) {// TODO Auto-generated catch blocklogger.error(e.getMessage(), e);}}}/*** 下载文件** @param remoteFtpPath FTP服务器保存目录* localPath* @param fileName 上传到FTP服务器上的文件名*/private boolean downloadFileByDo(String remoteFtpPath, String localPath, String fileName) {try {boolean changedir = ftpClient.changeWorkingDirectory(remoteFtpPath);if (!changedir) {logger.info("切入目录失败!");return false;}ftpClient.setBufferSize(1024);//解决上传中文 txt 文件乱码ftpClient.setControlEncoding("utf-8");FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_NT);conf.setServerLanguageCode("zh");// 设置文件类型(二进制)ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);FTPFile[] files = ftpClient.listFiles();for (int i = 0; i < files.length; i++) {try {if (fileName.equals(files[i].getName())) {downloadFile(files[i], localPath, remoteFtpPath);return true;}} catch (Exception e) {logger.error("下载异常", e);logger.error("<" + files[i].getName() + ">下载失败");}}} catch (IOException e) {// TODO Auto-generated catch blocklogger.error(e.getMessage(), e);return false;} finally {try {if (is != null) {is.close();}} catch (IOException e) {// TODO Auto-generated catch blocklogger.error(e.getMessage(), e);}}return true;}/*** 下载FTP文件* 当你需要下载FTP文件的时候,调用此方法* 根据<b>获取的文件名,本地地址,远程地址</b>进行下载** @param ftpFile* @param relativeLocalPath* @param relativeRemotePath*/private void downloadFile(FTPFile ftpFile, String relativeLocalPath, String relativeRemotePath) {if (ftpFile.isFile()) {if (ftpFile.getName().indexOf("?") == -1) {OutputStream outputStream = null;try {File entryDir = new File(relativeLocalPath);//如果文件夹路径不存在,则创建文件夹if (!entryDir.exists() || !entryDir.isDirectory()) {entryDir.mkdirs();}File locaFile = new File(relativeLocalPath + ftpFile.getName());//判断文件是否存在,存在则返回if (locaFile.exists()) {return;} else {outputStream = new FileOutputStream(relativeLocalPath + ftpFile.getName());ftpClient.retrieveFile(ftpFile.getName(), outputStream);outputStream.flush();outputStream.close();}} catch (Exception e) {logger.error("下载异常", e);} finally {try {if (outputStream != null) {outputStream.close();}} catch (IOException e) {logger.error("输出文件流异常");}}}} else {String newlocalRelatePath = relativeLocalPath + ftpFile.getName();String newRemote = new String(relativeRemotePath + ftpFile.getName().toString());File fl = new File(newlocalRelatePath);if (!fl.exists()) {fl.mkdirs();}try {newlocalRelatePath = newlocalRelatePath + '/';newRemote = newRemote + "/";String currentWorkDir = ftpFile.getName().toString();boolean changedir = ftpClient.changeWorkingDirectory(currentWorkDir);if (changedir) {FTPFile[] files = null;files = ftpClient.listFiles();for (int i = 0; i < files.length; i++) {downloadFile(files[i], newlocalRelatePath, newRemote);}}if (changedir) {ftpClient.changeToParentDirectory();}} catch (Exception e) {logger.error("下载异常", e);}}}/*** 下载文件** @param remoteFtpPath FTP服务器保存目录* localPath* @param fileName 上传到FTP服务器上的文件名*/public File getFtpFile(String remoteFtpPath, String fileName) {connect();File file = null;try {boolean changedir = ftpClient.changeWorkingDirectory(remoteFtpPath);if (!changedir) {logger.info("切入目录失败!");return file;}ftpClient.setBufferSize(1024);//解决上传中文 txt 文件乱码ftpClient.setControlEncoding("utf-8");FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_NT);conf.setServerLanguageCode("zh");// 设置文件类型(二进制)ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);FTPFile[] files = ftpClient.listFiles();for (int i = 0; i < files.length; i++) {try {if (fileName.equals(files[i].getName())) {InputStream fis = ftpClient.retrieveFileStream(files[i].getName());file = new File("drtext.xlsx");OutputStream os = new FileOutputStream(file);int bytesRead = 0;byte[] buffer = new byte[1024];while ((bytesRead = fis.read(buffer, 0, 1024)) != -1) {os.write(buffer, 0, bytesRead);}os.close();fis.close();return file;}} catch (Exception e) {logger.error("读取异常", e);}}close();} catch (IOException e) {// TODO Auto-generated catch blocklogger.error(e.getMessage(), e);} finally {try {if (is != null) {is.close();}} catch (IOException e) {// TODO Auto-generated catch blocklogger.error(e.getMessage(), e);}}return file;}public String getUserName() {return userName;}public void setUserName(String userName) {this.userName = userName;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public String getFtpHostName() {return ftpHostName;}public void setFtpHostName(String ftpHostName) {this.ftpHostName = ftpHostName;}public int getPort() {return port;}public void setPort(int port) {this.port = port;}public OutputStream getOs() {return os;}public void setOs(OutputStream os) {this.os = os;}}
本地单元测试代码如下:
package com.jinyu.test;import io.platform.base.common.utils.FtpUtils;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;import java.io.FileInputStream;/*** @description:* @author: zheng* @date: Created in 2021/2/24 9:32* @version: 0.0.1* @modified By:*/
public class FtpUtilsTests {private static FtpUtils ftpUtils = new FtpUtils();private static String ftpHostName = "xxxx";private static int ftpPort = 21;private static String ftpUserName = "xx";private static String ftpPassword = "xxx";@BeforeClasspublic static void init() {ftpUtils.setFtpHostName(ftpHostName);ftpUtils.setPort(ftpPort);ftpUtils.setUserName(ftpUserName);ftpUtils.setPassword(ftpPassword);}@Testpublic void testUploadFile() throws Exception {String localFilePath = "e:\\Login_bg.png";java.io.InputStream in = new java.io.FileInputStream(localFilePath);boolean uploadResult = ftpUtils.uploadFile("file", "1.png", in);Assert.assertEquals(uploadResult, true);}
}
本地测试是没问题的。
2、问题分析
通过多次测试与对华为云服务器的观察发现,FTP服务器是通过IIS站点开启的,默认使用的是主动模式,关于FTP的PORT(主动模式)和PASV(被动模式)
(1) PORT(主动模式)
PORT中文称为主动模式,工作的原理: FTP客户端连接到FTP服务器的21端口,发送用户名和密码登录,登录成功后要list列表或者读取数据时,客户端随机开放一个端口(1024以上),发送 PORT命令到FTP服务器,告诉服务器客户端采用主动模式并开放端口;FTP服务器收到PORT主动模式命令和端口号后,通过服务器的20端口和客户端开放的端口连接,发送数据。
(2) PASV(被动模式)
PASV是Passive的缩写,中文成为被动模式,工作原理:FTP客户端连接到FTP服务器的21端口,发送用户名和密码登录,登录成功后要list列表或者读取数据时,发送PASV命令到FTP服务器, 服务器在本地随机开放一个端口(1024以上),然后把开放的端口告诉客户端, 客户端再连接到服务器开放的端口进行数据传输。
也就是说在FTP服务器工作在主动模式下,应用服务器作为FTP客户端时每次建立连接都需要开放一个随机端口(1024),而华为云在网络控制台->访问控制->安全组下是对入口端口有限制的,为了安全我们不会开放所有的端口,也没办法为随机开启的端口动态开放端口限制。因此我们需要把FTP服务器配置为被动模式工作,并且需要在FTP防火墙支持中指定数据通道端口范围,这样就可以在安全组中配置入口端口为这个指定的端口范围。
3、配置FTP服务器为被动模式
只要在FTP服务器的"FTP防火墙支持"中配置了数据通道端口范围和防火墙的外部IP地址,重启服务器后,FTP服务器就自动工作在被动模式下了。
1、在IIS中选中左侧的服务器节点,然后双击中间面板中的FTP防火墙支持,如下图:
2、打开FTP防火墙支持的配置界面,配置相关参数,并单击“应用”,如下图。
- 数据通道端口范围:指定用于被动连接的端口范围。可指定的有效端口范围为1025-65535。请根据实际需求进行设置。
- 防火墙的外部IP地址:输入该弹性云服务器的公网IP地址。
3、重启云服务器使防火墙配置生效。
4、在华为云控制台设置安全组及防火墙
搭建好FTP站点后,需要在弹性云服务器安全组的入方向添加一条放行FTP端口的规则。
如果配置了“配置FTP防火墙支持”,需要在安全组中同时放行FTP站点使用的端口和FTP防火墙使用的数据通道端口。
服务器防火墙默认放行TCP的21端口用于FTP服务。如果选用其他端口,需要在防火墙中添加一条放行此端口的入站规则。
1、登录管理控制台。
2、单击管理控制台左上角的,选择区域和项目。
3、选择“计算 > 弹性云服务器”。
4、在弹性云服务器列表,单击待变更安全组规则的弹性云服务器名称。系统跳转至该弹性云服务器详情页面。
5、选择“安全组”页签,并单击,查看安全组规则。
6、单击安全组ID。系统自动跳转至安全组页面。
7、在“入方向”页签下,单击“添加规则”,配置安全组入方向的访问规则。根据业务需要,将源地址设置为允许已知IP地址所在的网段访问该安全组。配置FTP防火墙支持中可指定的有效端口范围为1025-65535,例如配置的数据端口范围为5000-6000。
结束
通过以上的配置,重新测试图片上传,发现功能已经正常了!