【VB.NET】FTP:WebException (550) ファイルが使用できません

MEMO

この記事は、私が http / https の URL と FTP の URL を混同してハマってしまった恥ずかしいお話です。

FTP のアップロードでエラーが出た

System.NET の WebClient や FtpWebRequest  を使って、Web サーバーに FTP でファイルをアップロードするコードを書いたんですヨ。

別に珍しくもない、よくある処理である。簡単であろう。楽勝である。と、思った。

コードを書き終えて、自信に満ち満ちて Visual Studio 上で F5 を押した。すると・・・

System.Net.WebException
HResult=0x80131509
Message=リモート サーバーがエラーを返しました: (550) ファイルが使用できません (例: ファイルが見つからない、ファイルへのアクセスがない)

こんなエラーが。

んなバナナ

スペルミスはない。パスは正しいように思える

アップロード先のサーバーのパスを間違えたか?

パスのどこかにスペルミスがあるのか?

ディスプレイが照れて赤くなるのではないかと思うくらい画面を凝視してチェックしてみたが、パスに間違いはなさそう。スペルミスもないゾ、と。

コードをいろいろいじって、やり方を変えて何度も試したけれど、同じエラー(または類似のエラー)が出る。

 

ファイルをアップロードしたいディレクトリは https://elleneast.com/Tools のディレクトリ。Web ブラウザからはこの URL でアクセスできる。

MEMO

実はこの URL からファイルを取得するプログラムを以前作ったことがあった。その動作に問題が無かったこともあり、(FTP の場合と混同して)FTP の場合もその URL が正しいと思い込んでしまう一因になった。

愛用の FTP ツール FileZilla でサーバーに接続したときは下図のように表示されている。

だから最初はアップロード先として ftp://elleneast.com/Tools/UploadedFile.txt を試したんだけど、エラーが出たので ftp://elleneast.com/public_html/Tools/UploadedFile.txt でも試してみた。けど、やっぱりエラーになった。

ftp://elleneast.com//xxx または ftp://elleneast.com/%2fxxx を試す

ftp://elleneast.com/xxx という(一般的な)指定をすると、これは相対パスを意味するので、FTP サーバーにログインした後(.NET Framework は)カレントディレクトリを
     <ログイン後の初期ディレクトリとして設定してある場所>/xxx
に移すらしい。

一方、ftp://elleneast.com//xxx まはた ftp://elleneast.com/%2fxxx(%2f は “/” のエスケープ表現)と指定すると、これは絶対パスを意味するので、カレントディレクトリは /xxx になるらしい。

(参考:Microsoft – FtpWebRequest Class

この挙動が原因でエラーになることもあるので、相対パスで指定してエラーになる場合は絶対パスに直して試してみると解決することもあるとか。

私の場合はこれでは解決しなかった。

FtpWebResponse.StatusDescription を調べるのも手

ちなみに、FTP 関連の例外エラーは .NET Framework が汎用的なメッセージに置き換えている場合があるので、下記のように FtpWebResponse.StatusDescription の内容を調べると、もっと根本的なエラーの原因が分かる場合があるらしい。

Dim oStream As System.IO.Stream = Nothing
Try
    oStream = oFtpWebReq.GetRequestStream()
Catch ex As  WebException
    MsgBox(DirectCast(ex.Response, FtpWebResponse).StatusDescription)
End Try

たとえば、このやり方で同じエラーを補足した場合、「550 elleneast.com/xxxxx: No such file or directory」というエラーメッセージを確認できました。

(参考:FTPでエラーが発生した場合に生のメッセージを取得するには?[2.0のみ、C#、VB]

Windows 標準の ftp コマンドで分かった真実

で、ふと思い出した。

遠い昔、コマンドプロンプトから  Windows 標準搭載の FTP コマンドを使ったことがあったっけ。

あれって、サーバーに接続、ディレクトリ変更、ファイルのアップロード・・・といったコマンドの1つ1つを手動で実行していくから、現在どういう状態なのか分かりやすいんだよね、と思い出した。

よし、あれで試してみよう。何か分かるかもしれない。

ftp で使える主なコマンド

Windows 標準の ftp で使える主な・・・というか最低限のコマンドは次の通りです。

open 指定したサーバに接続する。
ls サーバのファイルとディレクトリの一覧を表示する。”ls -l” と入力すると詳細を表示する。
cd

ディレクトリを変更する。たとえば “cd Tools” と入力すると Tools ディレクトリに移動する。”cd ..” と入力すると1つ上のディレクトリに移動する。

bye 接続を切断して ftp を終了する。
? ftp コマンドの説明を表示する。たとえば “? ls” と入力すると ls コマンドの説明を表示する。

で、コマンドプロンプトを開いて、ftp と入力。プロンプトが ftp> に変わる。

続いてサーバーに接続するために open elleneast.com と入力。ユーザー名とパスワードを入力すると無事ログインできた。

いま elleneast.com を開いたわけだから、ここでファイル一覧を表示させれば Tools ディレクトリがあるはず。と思って ls を実行。「うむ。やっぱりあった」と思って Tools ディレクトリに入ろうと cd Tools を実行すると・・・あれ?!

「No such file or directory.」「そんなファイルとかディレクトリとかねーよ」って・・・?

ちゃんと Tools ディレクトリが表示されてるのに変だなと思いつつ、詳細表示してみようと思って ls -l と入力。すると・・・

Tools ディレクトリ・・・だとばかり思ってたのに、行頭にディレクトリを示す d がありません。これディレクトリじゃないゾ!と気付いたわけです。

MEMO

ls -l コマンドで詳細表示をした場合、1文字目が d ならディレクトリ、l ならシンボリックリンク、- なら普通のファイルであることを意味します。

どうりで、アップロード先を ftp://elleneast.com/Tools/UploadFile.txt として試したコードがエラーになったわけだ。と納得。

じゃぁどこに本物の Tools ディレクトリがあるんだろうと cd, ls を繰り返して見つけた場所がここ。

最初に開いた場所/elleneast.com/public_html/Tools

それって、つまり、最初に開いた場所が elleneast.com だから、

elleneast.com/elleneast.com/public_html/Tools

ってことになるわけ? elleneast.com がだぶっちゃいますヨ??

ご冗談を ( ´艸`) と思いつつ・・・念のためアップロード先の URL を下記に修正して自作コードによる FTP アップロードを試したら・・・

ftp://elleneast.com/elleneast.com/public_html/Tools/someFile.txt

・・・転送成功!!

ま~~ぢ~~~か~~~~~。

当サイトの FTP URL の実態がこんな変ちくりんな状態になっているとは知らなかった。

と言っても最初の elleneast.com は本物のサーバー名のエイリアスなので、下記の URL でも自作コードによる FTP アップロードは成功した。

ftp://本物のサーバー名/elleneast.com/public_html/Tools/someFile.txt

ん~、そういうことか。

結論

ブラウザ(http / https)の URL をそのまま FTP の URL に転用できないことがあるので注意しましょう。

あったりまえじゃん

という声が聞こえてきそうです。

お恥ずかしい。(*ノωノ)

http / https の URL は実体とは異なるエイリアス(仮想ディレクトリ)を含んでいることがあるので、そのまま ftp の URL に使えるとは限らないわけですね(ftp は http / https のエイリアスを理解しない)。

そして、FTP で使用する正確なパスを(Windows 標準の ftp などで)きちんと調べるようにしましょう!

チャンチャン。

追記:FtpWebRequest 、WebClient、 WebRequest は使うな!

今回の件を調べているうちに知ったのですが、System.Net の FtpWebRequest クラス、WebClient クラス、WebRequest(HttpWebRequest 含む)クラスの使用は現在推奨されていないようです。

We don’t recommend that you use the FtpWebRequest class for new development.

For more information and alternatives to FtpWebRequest, see WebRequest shouldn’t be used on GitHub.

(引用:Microsoft – FtpWebRequest Class

 

We don’t recommend that you use the WebClient class for new development. Instead, use the System.Net.Http.HttpClientclass.

(引用:Microsoft – WebClient Class

 

We don’t recommend that you use WebRequest or its derived classes for new development. Instead, use the System.Net.Http.HttpClient class.

(引用:Microsoft – WebRequest Class

 

WebRequest-based APIs are on life-support only (that is, only critical fixes, no new improvements, enhancements).

(引用:GitHub – WebRequest shouldn’t be used

 

現在では

  • WebClient のかわりに HttpClient の使用が推奨されています。
  • WebRequest のかわりに HttpClient の使用が推奨されています。
  • FtpWebRequest のかわりにサードパーティの FTP クライアントの使用が推奨されています。(

 

参考記事:【VB.NET】FluentFTP を使ってみた

 

購読する
通知を受け取る対象
guest
0 Comments
Newest
Oldest
Inline Feedbacks
View all comments