トップ回答者
asp.netでテキストファイルをダウンロードすると、テキストに変な文字がくっついてきます。

質問
-
マイクロソフトコミュニティから移動してきました。よろしくお願いします。
asp.net 2010 (Professional)、IE9でダウンロードページを作成しています。
サーバサイド処理に、ファイルダウンロードのコードを書いています。
ファイルはダウンロードできたのですが、ダウンロードしたテキストファイル(拡張子が.txtや.log)
をメモ帳で開くと、ファイルの末尾に、元のファイルにはない文字が書かれてしまいます。
テキストファイルの末尾に書かれている文字は、ダウンロード画面のマークアップ(DownloadPage.aspx)の内容です。
■DownloadPage.aspx.vb
Dim strTempPath As String = "C:\Temp\aaaaa.txt"
Dim strDownloadFileName As String = "bbbbb.txt"
With Response
.ContentType = "application/octet-stream"
.HeaderEncoding = System.Text.Encoding.GetEncoding("Shift_JIS")
.AppendHeader("Content-Disposition", "attachment;filename=" + Server.UrlEncode(strDownloadFileName))
.WriteFile(strTempPath)
.Flush()
.End()
End With
■ダウンロードしたテキストファイルに余分に書かれている文字<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" ttp://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd>
<html xmlns=ttp://www.w3.org/1999/xhtml >
<head><title>
ダウンロード画面
</title><link id="incCssCommon" href="../test.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="../jquery-1.5.1.min.js"></script>
<script type="text/javascript">
・・・ 以下省略 ・・・
なぜこんなことになるのかわかりません。 どうしたら、末尾の文字なしのファイルがダウンロードできますか。
ちなみに、 同じ処理を拡張子=PDFのファイルを使った場合には問題は起こりません。
回答
-
以下のスレッドに書いてあることと同じ原因ではないですか?
HttpResponse.WriteとかWriteFileするとデフォルトで付いてしまう<!DOCTYPE html PUBLIC "-//W3C//DTD ・・・>タグを消すには?
http://social.msdn.microsoft.com/Forums/ja-JP/aspnetja/thread/b7b5e136-e8bd-457b-8993-aaa9893902ae
アップされたコードには End メソッドがありますが、<!DOCTYPE ... がくっついてくるということですと、理由不明ですが End では終わってなくて、Page の html コードをすべて送信してから終了しているとしか考えられません。
すべての返信
-
以下のスレッドに書いてあることと同じ原因ではないですか?
HttpResponse.WriteとかWriteFileするとデフォルトで付いてしまう<!DOCTYPE html PUBLIC "-//W3C//DTD ・・・>タグを消すには?
http://social.msdn.microsoft.com/Forums/ja-JP/aspnetja/thread/b7b5e136-e8bd-457b-8993-aaa9893902ae
アップされたコードには End メソッドがありますが、<!DOCTYPE ... がくっついてくるということですと、理由不明ですが End では終わってなくて、Page の html コードをすべて送信してから終了しているとしか考えられません。 -
SurferOnWwwさんありがとうございます。
教えていただいたページの現象と同じです。
それで、そのページのさらにリンク
ttp://surferonwww.info/BlogEngine/post/2013/02/16/use-http-handler-for-downloading-files.aspx
に書いてあったとおりに、ashxファイルを作ってみたのですが、やはり同じ結果になりました。
ashxの呼び出し方、間違っていますか。
■Handler1.ashx.vb
Imports System.Web
Imports System.Web.ServicesPublic Class Handler1
Implements System.Web.IHttpHandlerPrivate _downloadFilePath As String = ""
Private _downloadFileName As String = ""Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
Dim response As HttpResponse = context.Response
Dim request As HttpRequest = context.RequestIf (request.Browser.Browser.ToUpper().IndexOf("IE") >= 0) Then
_downloadFileName = context.Server.UrlEncode(_downloadFileName)
End Ifresponse.AppendHeader("Content-Disposition", "attachment;filename=" + _downloadFileName)
response.ContentType = "text/plain"
response.TransmitFile(_downloadFilePath)
'response.Write("Hello World")End Sub
ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
Get
Return False
End Get
End PropertyPublic Sub New(ByVal strTempPath As String, ByVal strDownloadFileName As String)
_downloadFilePath = strTempPath
_downloadFileName = strDownloadFileName
End Sub
End Class■ダウンロードページからの呼び出し
Dim cls As New Handler1(strTempPath, strDownloadFileName)
cls.ProcessRequest(Me.Context)よろしくお願いします。
-
少し直してみたら動くようになりました。
ashxも、aspxと同じように呼び出せばよかったのですね。
引数はQueryStringで渡すようにしました。
・ashx.vbのNewを削除
・ProcessRequestの中で、QueryStringを取得
・呼出側はResponse.Redirectでashxを呼び出す
■Handler1.ashx.vb
Imports System.Web
Imports System.Web.ServicesPublic Class Handler1
Implements System.Web.IHttpHandlerSub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
Dim response As HttpResponse = context.Response
Dim request As HttpRequest = context.RequestDim strFilePath As String = request.QueryString("path")
Dim strDownloadFileName As String = request.QueryString("filename")If (request.Browser.Browser.ToUpper().IndexOf("IE") >= 0) Then
strDownloadFileName = context.Server.UrlEncode(strDownloadFileName)
End Ifresponse.AppendHeader("Content-Disposition", "attachment;filename=" + strDownloadFileName)
response.ContentType = "text/plain"
response.TransmitFile(strFilePath) ' 指定したファイル
'response.Write("Hello World") ' 文字列を出力する場合はこちらEnd Sub
ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
Get
Return False
End Get
End PropertyEnd Class
■呼出側
Response.Redirect("~/・・・/Handler1.ashx?path=" & strTempPath & _
"&filename=" & strDownloadFileName)
ashxファイル、初めて使いました。勉強になりました。
SurferOnWwwさん、本当にありがとうございました。
-
> ashxも、aspxと同じように呼び出せばよかったのですね。
>
> 引数はQueryStringで渡すようにしました。そうです、それでいいと思います。
> ・呼出側はResponse.Redirectでashxを呼び出すHttpResponse.Redirect メソッド (String) は非推奨の End メソッドを呼び出しますので注意してください(ThreadAbortException 例外をスローするので、アプリケーションのパフォーマンスに悪影響があります)。
HttpResponse.Redirect メソッド (String)
http://msdn.microsoft.com/ja-jp/library/vstudio/t9dwyts4.aspx上のページに書いてあるように、HttpResponse.Redirect(String, Boolean) オーバーロードを使用するのがお勧めだそうです。
-
フォーラム オペレーターの星 睦美です。
SurferONWww さん、なちゃ さん アドバイスありがとうございます。
saZQ さん、こんにちは
私のほうで今回の質問の解決に役立った情報としてSurferONWww さんの返信に[回答の候補に設定] させていただきました。
コミュニティで良い回答を共有するために、投稿者から参考になった返信に[回答としてマーク]をお願いします。なちゃ さんからのアドバイスにさらに質問がありましたら、質問と回答が分かりやすいスレッドになるように新しいスレッドを作成していただければと思います。
それではこれからもMSDN フォーラムをお役立てください。日本マイクロソフト株式会社 フォーラム オペレーター 星 睦美
-
> セッション管理のコード、追加してみます。
「セッション管理」とはどういう意味かわかりませんが、何にせよ、ワーカープロセスのアクセス権の設定で対応可能だと思いますが。
だめですよ。
それでは、例えばWeb.configとかをダウンロードできたり等々してしまいます。
ちょっと単純に権限設定とかではできません。ではどうするかということなのですが、そもそもこのダウンロードのプログラムがどういう目的のものか、どういうファイルをダウンロードするものかなどに依存してきますので、単純にひとつの解があるというような話でもありません。
例えば特定のダウンロード用フォルダを決めて、そこ以外を完全にはじく(これもチェックはそれなりに注意が必要)ようにするというようなやり方もあるでしょうし、あるいはファイル名指定ではなくID指定で対応するファイルのみダウンロードできるように制御する(考え方的には可能ならこちらの方がお勧め)など方法はいろいろ考えられますが、どういう方法がよいかというと、どういうダウンロード機能なのかによっても変わってきます。
-----追記
あ、もしかすると、偽装して権限設定で、とか言われるかもしれませんが、それも含めて権限設定で制御するのはお勧めできません。
-----さらに追記
何度もすみません、一時的にだけ偽装してというのならありかもしれません(お勧めかというとやや微妙ですが)。
ただ、偽装した状態でTransmitFileとかが普通に使えるのかは試してないのでちょっとわかりません。- 編集済み なちゃ 2013年4月10日 1:32
-
> だめですよ。
断定的ですね。ダメかどうかは質問者さんが判断することだと思います。
> 単純にひとつの解があるというような話でもありません。
というのはその通りだと思います。なので、ワーカープロセスのアクセス権の設定で対応するのも、質問者さんの環境では解になるかもしれません。
質問者さんの最初の質問に、
> Dim strTempPath As String = "C:\Temp\aaaaa.txt"
とありましたので、アプリケーションルートではない特定のフォルダにダウンロードするファイルがあるようです。その状態で、
> URLを手で打ち込んでみたら、おっしゃるとおり何でもダウンロード
> できてしまいました。とのことですので、ワーカープロセスのアクセス権の設定に問題があって、本来アクセスを許すべきでないフォルダまでアクセスできてしまう状況ではないでしょうか?
であれば、ワーカープロセスに、適切に、C:\Temp フォルダに対するアクセス権のみ与えておけば、問題は解決するかもしれません。そのあたりは質問者さんに聞かないと分かりませんが。
-
> いやダメでしょう。
> いくらなんでも常識的な範囲というものがあるでしょう。一般的に「常識的な範囲」というのは普遍ではなくて、環境・要件によって変わってくるはずです。
質問者さんの環境・要件を知らない第三者と、質問者さんが共有できないかもしれない第三者の「常識」をベースに議論しても意味がなさそうですので、質問者さんから「自分の環境はこうだから、こういう理由で、ワーカープロセスのアクセス権の設定だけでは解決しない」というようなダメ出しがあったら、その時点でまた解決策を議論したいと思います。
> そんな状態でASP.NETは実行できるのですか?そのあたりも「常識的な範囲」の違いによる誤解なのかもしれません。
先の私のレスを、ワーカープロセスには、アプリケーションルートにアクセス権を与えず、C:\Temp フォルダにのみ与えると解釈しましたか?
自分としてはそんなこと(アプリケーションルートにアクセス権を与えない)は考えてもいませんでしたが、そういう解釈をされる方がいたとしたら、自分の「常識的な範囲」を超えていたようで、先の私のレスは言葉足らずだったようです。
-
> いやダメでしょう。
> いくらなんでも常識的な範囲というものがあるでしょう。一般的に「常識的な範囲」というのは普遍ではなくて、環境・要件によって変わってくるはずです。
質問者さんの環境・要件を知らない第三者と、質問者さんが共有できないかもしれない第三者の「常識」をベースに議論しても意味がなさそうですので、質問者さんから「自分の環境はこうだから、こういう理由で、ワーカープロセスのアクセス権の設定だけでは解決しない」というようなダメ出しがあったら、その時点でまた解決策を議論したいと思います。
99%常識でやるべきでないようなことを言い張って何か意義があるんですかね?
----追記ここから
99%とか書きましたが、これは単にほとんど程度の意味ですが、これでは言いたいことを正確に表現できていないのでちょっと訂正します。
環境によって問題が発生しないことはあり得るかもしれませんが、たとえ実害がなくともやってはいけないことであるのは常識です。
まるで私が勝手に常識と言ってるだけに見えているのかもしれませんが、例えばSQLインジェクションはダメというのと同様の意味でだめです。
SQLインジェクションの脆弱性があっても実害のない環境はあり得るかもしれませんが、それでもやってはいけないことであるのは常識です。質問者の環境ではSQLインジェクションがあっても実害はないかもしれないので、第三者が言っても意味がないとか言うんでしょうか?
今回のは、例えて言うならあなたが、SQLインジェクションの脆弱性があるようなやり方を示した、というような状況ですよ。----追記ここまで
しかも最初にあなたは何と言って提案しましたか?これでできると思いますけどくらいの軽い提案でしたね?
一体どれほどのリスクを抱える提案か、一言でも補足なり注意をしましたか?最初は問題点を失念しただけかと思いましたが、あくまで本気の提案で特に補足する気もなかったということでしたか。
> そんな状態でASP.NETは実行できるのですか?
そのあたりも「常識的な範囲」の違いによる誤解なのかもしれません。
先の私のレスを、ワーカープロセスには、アプリケーションルートにアクセス権を与えず、C:\Temp フォルダにのみ与えると解釈しましたか?
自分としてはそんなこと(アプリケーションルートにアクセス権を与えない)は考えてもいませんでしたが、そういう解釈をされる方がいたとしたら、自分の「常識的な範囲」を超えていたようで、先の私のレスは言葉足らずだったようです。
であればなおさら、危険も、アプリケーション内のあらゆるファイルをクライアントからダウンロード可能のままであることも、何もかもわかったうえでこれでできるのでは?と提案したのですね。
ところでASP.NETはアプリケーションのルート以外に読み取り権限は不要で動作するんでしょうか?
詳細は私も分かりませんが、それでは動くはずがないと思います。もしTempにだけ読み取り権限を与えればよいというのであれば、ASP.NETが問題なく実行できて、その上でTemp以外の不要なフォルダの読み取り権限を完全に外す方法くらいは提示してほしいです。私も知りたい。
で、そのうえで、どのくらいのファイルがクライアントからダウンロードできるのか、質問者が問題ないか判断できるように情報を提示してください。
今のままではそもそも質問者に判断できるような情報がありません。- 編集済み なちゃ 2013年4月11日 15:36
-
あと、これはもうつまるところ見解の相違なのでしょうけれど、Webアプリケーションにおいて、Webアプリケーションのルート配下のあらゆるファイルをクライアントからダウンロードできるような状態は、避けるかべきかどうかは人それぞれだとか、そんなあえてやったりするようなことなんでしょうか?
ASPXファイルやソースファイルも(プリコンパイル等々でない環境はあるにしても)、設定ファイルも、dllも、アプリが何等かアクセスするファイルも、標準のDBファイルを使っていればそのファイルも、何もかもクライアントからダウンロードできるのですよ?
アプリケーションに何かファイル関係を追加するたびに、このファイルがダウンロード可能で問題ないか確認して、もし問題あればその時点で破綻するのですよ?
その上、マシン内の他のファイルも、これはどこまでか把握もできませんが、あちこちにダウンロード可能なファイルが存在することになるでしょう。
もしファイル共有なんか利用したらどうなるか。こんなの、常識で最初から止めとくしか、私には考えられません。