FTPファイルダウンロード時にブラウザがファイルを直接表示してしまう問題の解決策

FTPクライアントツールとして、IIS7サーバーマネージャーを推奨します。 このツールはFTPサイトの一括管理と定期的なアップロード・ダウンロード機能を提供します。 サーバー統合管理ツールとして、WindowsとLinuxシステム、VPSのサーバーを一括で管理できるのが最大の特徴です。 ウェブマスターおよびサーバー運用担当者の作業効率を大幅に向上させます。 また、IIS7サーバーマネージャーはVNCクライアントとしても機能し、サーバーを一元的に管理できるため非常に便利です。

FTPサーバーを構築してユーザーがアップロード・ダウンロードできるようにしましたが、ダウンロード中にテキストファイルや画像ファイル(txt、jpg、png、pdfなど)がブラウザ上で直接表示され、ダウンロードされない問題が発生しました。

以下の方法で解決策を見つけました:

最も簡単な方法: txtファイルを右クリックして「リンクを別名で保存」を選択すると、直接ダウンロードできます。

1:FTPディレクトリ内の.htaccessファイルを編集する方法 このファイルはファイルタイプのマッピングを行うもので、各ファイルタイプをoctet-streamタイプに変換することで、ブラウザによる解析を防ぎます。 しかし、FTPディレクトリに該当ファイルが見つからず、FileZillaを使用してサーバーに接続しても「隠しファイルを強制表示」オプションを有効にしてもファイルが表示されませんでした。 Apache専用のファイルであるとの情報があり、使用しているvsftpdサーバーでは存在しない可能性があるため、断念しました。

2:Ajaxを使用した方法 ファイルの出力ストリーム(OutputStream)をコールバック結果として返す方法です。 HTMLコードは以下の通り、バックエンドコードは方法4と同じです。


<html lang="en">
<head>
    <script type="text/javascript" src="/js/jquery-3.0.0.min.js"></script>
    <meta charset="UTF-8">
    <title>タイトル</title>

    <script>
    function link() {
        $.ajax({
            type: "get",
            url: "downloadFileByOutputStream",
            data: {
                "filename":'homepage.png'
                 },
            async: true,
            success: function (flag) {
                if (flag != "") {
                console.log(flag);
                       var obj = eval(flag);
                       localStorage['UsertypeSelect']=JSON.stringify(obj);
                    };
            }
        });
}
</script>
</head>
<body>
    <a href="javascript:void(0)" onclick="link()">OutputStreamによるダウンロード</a>
</body>
</html>

実行後、データが文字化けし、eval(flag)による変換に失敗しました。

3:PrintWriterストリームを使用する方法 隠しフォームを使ってストリームをコールバックする方法です。 テキストファイルやドキュメントファイル(txt、docなど)は正常にダウンロード可能ですが、画像などのバイナリファイルはダウンロードできません。

フロントエンドコード:


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>タイトル</title>
    <script type="text/javascript" src="/js/jquery-3.0.0.min.js"></script>
    <script>
    function download(){
    console.log('実行中');
        downloadTemplate('/downloadFileByPrintWriter', 'filename', 'homepage.png');
    }
    function downloadTemplate(action, type, value){
    console.log(action);
        var form = document.createElement('form');
        document.body.appendChild(form);
        form.style.display = "none";
        form.action = action;
        form.id = 'download';
        form.method = 'post';

        var newElement = document.createElement("input");
        newElement.setAttribute("type","hidden");
        newElement.name = type;
        newElement.value = value;
        form.appendChild(newElement);
        form.submit();
    }
    </script>
</head>
<body>

<span onclick="download()">PrintWriterによるダウンロード</span>

</body>
</html>

バックエンドコード:

   /**
     * 指定されたファイル名でダウンロードを行う
     * 説明: FTPサーバーからファイルをダウンロード
     * @param filename ダウンロードするファイル名
     * @return
     */
    @RequestMapping("/downloadFileByPrintWriter")
    @ResponseBody
    public String downloadFileByPrintWriter(HttpServletResponse response, String filename) throws IOException {
        FTPClient ftp = new FTPClient();
        try {
            int reply;
            ftp.connect(host, port);
            ftp.login(username, password);
            ftp.enterLocalPassiveMode();

            reply = ftp.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                ftp.disconnect();
                return "FTP接続なし";
            }
            ftp.changeWorkingDirectory(publicFilePath);
            logger.debug("リモートパス" + publicFilePath);
            FTPFile[] fs = ftp.listFiles();
            for (FTPFile ff : fs) {
                logger.debug("リモートファイル名" + ff.getName());
                if (ff.getName().equals(filename)) {
                    InputStream in = ftp.retrieveFileStream(ff.getName());
                    int len = 0;
                    byte[] buff = new byte[1024];
                    response.reset();
                    response.setContentType("application/octet-stream");
                    response.addHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");
                    InputStreamReader inputStreamReader = new InputStreamReader(in);

                    PrintWriter fw = response.getWriter();

                    BufferedReader bf = new BufferedReader(inputStreamReader);
                    char[] chs = new char[1024];
                    String str=null;
                    while ((str = bf.readLine()) != null) {
                        fw.write(str);
                        fw.flush();
                    }
                    fw.flush();
                    in.close();
                    fw.close();
                    return "成功";
                }
            }
            ftp.logout();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (ftp.isConnected()) {
                try {
                    ftp.disconnect();
                } catch (IOException ioe) {
                }
            }
        }
        return "ダウンロード失敗";
    }

4:OutputStreamストリームを使用する方法(成功) 隠しフォームを使ってストリームをコールバックする方法で正常に動作しました。

HTMLコード:


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>タイトル</title>
    <script type="text/javascript" src="/js/jquery-3.0.0.min.js"></script>
    <script>
    function download(){
    console.log('実行中');
        downloadTemplate('/downloadFileByOutputStream', 'filename', 'homepage.png');
    }
    function downloadTemplate(action, type, value){
    console.log(action);
        var form = document.createElement('form');
        document.body.appendChild(form);
        form.style.display = "none";
        form.action = action;
        form.id = 'download';
        form.method = 'post';

        var newElement = document.createElement("input");
        newElement.setAttribute("type","hidden");
        newElement.name = type;
        newElement.value = value;
        form.appendChild(newElement);
        form.submit();
    }
    </script>
</head>
<body>

<span onclick="download()">PrintWriterによるダウンロード</span>

</body>
</html>

バックエンドコード:

  /**
     * 指定されたファイル名でダウンロードを行う
     * 説明: FTPサーバーからファイルをダウンロード
     * @param filename ダウンロードするファイル名
     * @return
     */
    @RequestMapping("/downloadFileByOutputStream")
    @ResponseBody
    public String downloadFileByOutputStream(HttpServletResponse response, String filename) throws IOException {
        logger.debug("OutputStreamによるダウンロード");
        FTPClient ftp = new FTPClient();
        try {
            int reply;
            ftp.connect(host, port);
            ftp.login(username, password);
            ftp.enterLocalPassiveMode();
            reply = ftp.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                ftp.disconnect();
                return "接続失敗";
            }
            ftp.changeWorkingDirectory(publicFilePath);
            logger.debug("リモートパス" + publicFilePath);
            FTPFile[] fs = ftp.listFiles();
            for (FTPFile ff : fs) {
                logger.debug("リモートファイル名" + ff.getName());
                if (ff.getName().equals(filename)) {
                    InputStream in = ftp.retrieveFileStream(ff.getName());
                    logger.debug(in.toString());
                    int len = 0;
                    byte[] buff = new byte[1024*1024];

                    response.reset();
                    response.setContentType("application/octet-stream");
                    response.addHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");
                    OutputStream out=response.getOutputStream();

                    while((len=in.read(buff))!=-1){
                        logger.debug("OutputStreamとして書き出し");
                        out.write(buff, 0, len);
                        out.flush();
                    }
                    in.close();
                    out.close();
                    return "成功";
                }
            }

            ftp.logout();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (ftp.isConnected()) {
                try {
                    ftp.disconnect();
                } catch (IOException ioe) {
                }
            }
        }
        return "失敗";
    }

タグ: FTP ブラウザ ダウンロード セキュリティ HTTPレスポンス

5月22日 03:26 投稿