- PR -

JSPで起こるJavaScriptエラー「アクセスが拒否されました」

投稿者投稿内容
maki
会議室デビュー日: 2007/03/13
投稿数: 7
お住まい・勤務地: 大阪府
投稿日時: 2007-03-28 14:09
いつもお世話になっております。

JSPからCSV出力したい情報をチェックボックスから選択し、
ダウンロードを行うというページを作成しています。

チェックボックスは6つ程あり、出力したい情報を複数選択できるのですが、
「全て」というチェックボックスを作成し、そのチェックボックスを押下すると全てのチェックボックスがONまたはOFF状態になるようにJavaScriptで制御を行っています。
また、ダウンロードボタン押下後の入力チェック→サブミットもJavaScriptでやっています。

発生する現象は、「全て」チェックボックス押下 または 「ダウンロード」ボタンを一度でも押下し、JavaScriptが一度でも動作してしまうと、その後どのような動作を行っても「アクセスが拒否されました」というサーブレットエラーが発生するというものです。
JavaScriptが一度でも動いてしまうと、「全て」チェックボックス、「ダウンロード」ボタンはもちろん、「全て」以外のJavaScriptを通らないはずの他のチェックボックスを押下した場合でも発生します。
ページをリロードすると正常に動作します。
また、IE6.0で発生し、NetScapeやFireFoxでは正常に動作します。同じIEでも6.0のServicePack2を当てているもので正常に動作したりとブラウザに依存するのかなと考えているのですが、解決策が分かりません。
http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=22620&forum=12&19
も参考にしたのですが。。
解決策が分かりませんので、どうかよろしくお願いいたします。


以下にソースを抜粋します。
<%@ page language="java" contentType="text/html;charset=Windows-31J"%>
<html>
<head>
<title>CSV出力</title>
〜略〜
<script language="JavaScript">
<!--
function CheckAll(sCheckBoxName, bCheck) {
var objForm = document.MainForm;
var oElement;
for(var i = 0; i < objForm.elements.length; i++) {
oElement = objForm.elements[i];
if (oElement.type == 'checkbox') {
if (oElement.name == sCheckBoxName) {
oElement.checked = bCheck;
}
if (sCheckBoxName == 'ALL') {
oElement.checked = bCheck;
}
if ((sCheckBoxName == 'cSEL') && (oElement.name.substring(0,4) == sCheckBoxName)) {
oElement.checked = bCheck;
}
}
}
}

function checkInput() {
var objForm = document.MainForm;
//必須チェック
if (chkChecked() == false) {
alert('選択されていません。');
return false;
}
return true;
}

function onExec(prog, act) {
document.MainForm.PROGRAM_ID.value = prog;
document.MainForm.ACTION_ID.value = act;
document.MainForm.submit();
}

function chkChecked() {
var oFrm = document.MainForm;
var oElement;
for(var i = 0; i < oFrm.elements.length; i++) {
oElement = oFrm.elements[i];
if (oElement.type == 'checkbox') {
sName = oElement.name;
if (sName.substring(sName.length-3,sName.length) != "ALL") {
if (oElement.checked == true) {
return true;
}
}
}
}
return false;
}
//-->
</script>
</head>
<body>
<form name="MainForm" method="post" action="../servlet/CsvServlet">
<input type="HIDDEN" name="PROGRAM_ID">
<input type="HIDDEN" name="ACTION_ID">
<B>出力対象情報</B>(複数指定可能)
<table cellpadding="4"><tr><td colspan="3">
<INPUT TYPE="checkbox" name="cSEL_ALL" value="1" onClick="CheckAll('cSEL_ALL', document.MainForm.cSEL_ALL.checked);">全て<br>
<INPUT TYPE="checkbox" name="cSEL_1" value="11">情報1<br>
<INPUT TYPE="checkbox" name="cSEL_2" value="12">情報2<br>
<INPUT TYPE="checkbox" name="cSEL_3" value="13">情報3<br>
<INPUT TYPE="checkbox" name="cSEL_4" value="14">情報4<br>
<INPUT TYPE="checkbox" name="cSEL_5" value="15">情報5<br>
<INPUT TYPE="checkbox" name="cSEL_6" value="16">情報6
</td></tr></table><BR>
<input TYPE="BUTTON" VALUE="ダウンロード" onClick="onExec('CSV', 'DOWNSTART');">
</form>
</body>
</html>

また、環境は以下の通りです。
JAVA:J2SDK1.4.2_X
サーバ:Oracle10iAS
開発環境:JDeveloper
IE:6.0

お忙しいところ長々と申し訳ありません。
よろしくお願いいたします。

[ メッセージ編集済み 編集者: maki 編集日時 2007-03-28 14:50 ]

[ メッセージ編集済み 編集者: maki 編集日時 2007-03-28 15:28 ]
すみょし
常連さん
会議室デビュー日: 2007/01/25
投稿数: 36
投稿日時: 2007-03-28 17:41
どうもはじめまして。

逆質問で申し訳ありませんが、このJSPは単一のフレームで実行されているのでしょうか?
CSVのダウンロード自体が、最初の一回目だけ成功する、と言うことで良いですか?
初回ダウンロードはOKで、画面はそのまま。
その後続けてダウンロードしようとすると、Scriptのエラーが発生する、と言うことでしょうか。

差し支えなければ呼び出しているServletのコードも教えていただけますか?

※たぶん隠しフレームを用意するかして、隠しフレームに対してCSVダウンロード用Servletを呼び出すように変更すればエラーが出なくなるような気がするのですが・・・
maki
会議室デビュー日: 2007/03/13
投稿数: 7
お住まい・勤務地: 大阪府
投稿日時: 2007-03-28 19:24
すみょしさん。はじめまして!
返答ありがとうございます!

引用:

逆質問で申し訳ありませんが、このJSPは単一のフレームで実行されているのでしょうか?


ページ自体は3つのフレームから成っていますが、
フレーム間のデータの受け渡しなどはなく、単一のJSP内で処理は完結します。

引用:

CSVのダウンロード自体が、最初の一回目だけ成功する、と言うことで良いですか?
初回ダウンロードはOKで、画面はそのまま。
その後続けてダウンロードしようとすると、Scriptのエラーが発生する、と言うことでしょうか。


その通りです。言葉足らずで申し訳ありません。

引用:

差し支えなければ呼び出しているServletのコードも教えていただけますか?


スーパークラスとか呼び出しているクラスとかを張るとすごく長くなるのですが、
それも張ったほうがよいでしょうか。
今回はとりあえず、呼び出しているクラスのみ記述します。

以下のクラスは共通で使っているクラスで、
別のXMLに処理を行うアクションクラスのパスが記述してあり、
そのXMLを読みに行き、アクションを実行しています。
アクションクラスではDBを検索して、CSV出力を行い、zipファイルに圧縮して
ダウンロードダイアログを表示させています。

=================================================================
package jp.co.test.csv;

import java.io.IOException;
〜略〜

/**
* CSV出力Servlet
*/
public class CsvServlet extends TestServlet {

/** エラーJSPのパス */
private static final String ERROR_JSP_PAGE = "./../jsp/ErrorPage.jsp";

/**
* サーブレットの初期化
*/
public void init(ServletConfig config) throws ServletException {
super.init(config);
}

/**
* HTTP.GETリクエストを処理します。
*/
protected void doGetService(ServletCondition condition)
throws TestException {
doAction(condition);
}

/**
* HTTP.POSTリクエストを処理します。
*/
protected void doPostService(ServletCondition condition)
throws TestException {
doAction(condition);
}

/**
* 処理を開始します。
* @param ServletCondition condition HTTP.リクエストをまとめて格納
* @exception TestException 処理中にエラーが発生した場合、スローされます。
*/
private void doAction(ServletCondition condition)
throws TestException {
try {
try {
/* HttpSessionチェック */
checkSession(condition);

/* XMLマップクラスのインスタンス取得 */
TestXmlProgram xml = TestProgram.getInstance();

/* アクションID、プログラムIDの取得 */
HttpServletRequest req = condition.getHttpServletRequest();
String actionId = req.getParameter(ACTION_ID).toString();
String programId = req.getParameter(PROGRAM_ID).toString();

if (actionId == null || actionId.equals("") || programId == null || programId.equals("")) {
// メッセージの取得に失敗しました。
throw TestLogger.logException(MessageManager.getMessage("F900101"), this);
}

/* アクションID、プログラムIDをKeyに処理クラス名を取得 */
String className = "";
className = xml.getActionClasses(programId, actionId);

TestActionable action = (TestActionBase) Class.forName(className, true, this.getClass().getClassLoader()).newInstance();
action.start(condition);

// Forwardページの取得
String pageForward = xml.getActionPageJsp(programId, actionId);
// Redirectパスの取得
String pageRedirect = xml.getActionPageRedirect(programId, actionId);

if (pageForward != null) {
// ForwardページへForward
RequestDispatcher dispatcher = servletContext.getRequestDispatcher(pageForward);
dispatcher.forward(condition.getHttpServletRequest(), condition.getHttpServletResponse());
} else if (pageRedirect != null) {
// RedirectパスへRedirect
pageRedirect = condition.getHttpServletResponse().encodeRedirectURL(UrlRedirectUtil.getSendRedirectPath(pageRedirect));
condition.getHttpServletResponse().sendRedirect(pageRedirect);
}

} catch (ClassNotFoundException cnfe) {
throw TestLogger.logException(MessageManager.getMessage("F000101"), cnfe, this);
} catch (IllegalAccessException iae) {
throw TestLogger.logException(MessageManager.getMessage("F000101"), iae, this);
} catch (InstantiationException inste) {
throw TestLogger.logException(MessageManager.getMessage("F000101"), inste, this);
} catch (ServletException se) {
throw TestLogger.logException(MessageManager.getMessage("F000101"), se, condition, this);
} catch (IOException ioe) {
throw TestLogger.logException(MessageManager.getMessage("F000101"), ioe, condition, this);
}

} catch (TestException ke) {
try {
condition.getHttpServletRequest().setAttribute("testException", ke);
condition.getHttpServletRequest().getRequestDispatcher(ERROR_JSP_PAGE)
.forward(condition.getHttpServletRequest(), condition.getHttpServletResponse());
} catch (Exception ex) {
throw TestLogger.logException(MessageManager.getMessage("F000101"), ex, condition, this);
}
throw ke;
} catch (Exception e) {
TestException ke = TestLogger.logException(MessageManager.getMessage("F000101"), e, condition, this);
try {
condition.getHttpServletRequest().setAttribute("testException", ke);
condition.getHttpServletRequest().getRequestDispatcher(ERROR_JSP_PAGE)
.forward(condition.getHttpServletRequest(), condition.getHttpServletResponse());
} catch (Exception ex) {
throw TestLogger.logException(MessageManager.getMessage("F000101"), ex, condition, this);
}
throw ke;
}
}

/**
* HTTPSessionチェック
* 各種処理のリクエストごとにセッションを保持しているか調べます。
* @param ServletCondtion condition HTTP.リクエストオブジェクトをまとめて格納
* @return true:チェック正常(セッション内にIDを確認した。)
* false:チェック異常(セッションがない、セッション内にIDがない)
* @exception TestException 処理中にエラーが発生した場合、例外がスローされます。
*/
private void checkSession(ServletCondition condition)
throws TestException {
try {
String Id = getId(condition.getHttpServletRequest());
HttpSession session = condition.getHttpServletRequest().getSession();
if (session == null) {
throw new TestException(MessageManager.getMessage("E000101"));
}
String id = (session.getAttribute("ID") == null ? "" : session.getAttribute("ID").toString());
if (id.equals("")) {
throw new TestException(MessageManager.getMessage("E000101"));
}
} catch (TestException ke) {
throw ke;
} catch (Exception e) {
throw new TestException(MessageManager.getMessage("F000101"));
}
}
}
=================================================================

引用:

※たぶん隠しフレームを用意するかして、隠しフレームに対してCSVダウンロード用Servletを呼び出すように変更すればエラーが出なくなるような気がするのですが・・・


それがよくわからないんですよね。。初心者ですみません。
JSPを隠しフレームで囲うとその部分が見えなくなっちゃうような。。

長々と申し訳ありません。
よろしくお願いいたします。
すみょし
常連さん
会議室デビュー日: 2007/01/25
投稿数: 36
投稿日時: 2007-03-28 19:48
返答ありがとうございます。

ソースを少し読みましたが、必ず、dispathcer.forward()か
sendRedirect()を行っていますよね。
また、提示いただいたソース中からActionクラスが呼ばれているとありましたが、
そのActionクラス内で、CSVを書き出していますよね。

makiさんが最初に書かれていたこちら(http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=22620&forum=12&19)の解答とほぼ一緒の内容なのですが、
Servlet中で1回以上のブラウザへの返答は受け付けられませんので、その辺が原因じゃないかなぁ、と思います。
(見当違いかもしれませんが)

また、
>JSPを隠しフレームで囲うとその部分が見えなくなっちゃうような。。

の件ですが、例えば、ファイルをダウンロードさせるServletの場合、
通常、ファイルをブラウザへ返すだけで、画面の遷移等は行いません。
その理由は
http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=22620&forum=12&19
に記述されていましたので御参照下さい。
(ファイルをブラウザに返してから、ページ遷移を行おうとするとおかしくなります)

ページ遷移を伴わないServletを呼び出す場合は、自フレームに影響を及ぼさない対象へリクエストを投げる必要があります。
その為、サイズ0のフレームに対してリクエストを投げるわけです。

同様な内容で悩んでるかたに、本会議室の人たちが挙げている解決策が、
「おまじない」のように「別フレームにリクエストを投げると良い」
と回答されているのはその為です。
mio
ぬし
会議室デビュー日: 2005/08/25
投稿数: 734
お住まい・勤務地: 神奈川県
投稿日時: 2007-03-28 20:13
JSPかどうかは関係ないですね。
そのページでダウンロードのアクションを起こすことで、ページ遷移が発生するはずが、見かけ上しないままに終わる。
しかし、表示中のドキュメント自体はアクションを起こした時点でいなくなるので、二度目からアクセスが拒否される。
これを防ぐには、アクションの出力先を隠しフレームにする、ということで。

で、JSPはクライアントにとってはただのHTMLなので、JSPかどうかで変わることはありません。
maki
会議室デビュー日: 2007/03/13
投稿数: 7
お住まい・勤務地: 大阪府
投稿日時: 2007-03-28 20:25
すみょしさん、mioさん返答ありがとうございます!

引用:

ソースを少し読みましたが、必ず、dispathcer.forward()か
sendRedirect()を行っていますよね。


ページ遷移を行わないように、xml内のフォワード先、リダイレクト先をnullにしており、
ファイルをブラウザに返しているだけで、ページ遷移は行われないはずです。

引用:

ページ遷移を伴わないServletを呼び出す場合は、自フレームに影響を及ぼさない対象へリクエストを投げる必要があります。
その為、サイズ0のフレームに対してリクエストを投げるわけです。


サイズ0のiframeをJSP内に作成し、target指定してsubmitした場合でも変わりませんでした。
やり方が間違っているのでしょうか。。以下のように変えてみたのですが。。
===========================================
function onExec(prog, act) {
document.MainForm.PROGRAM_ID.value = prog;
document.MainForm.ACTION_ID.value = act;
document.MainForm.TARGET = "test";
document.MainForm.submit();
</script>
</head>
<body>
<iframe src="" name="test" width="0" height="0"></iframe>
<form name="MainForm" method="post" action="../servlet/CsvServlet">
===========================================

引用:

しかし、表示中のドキュメント自体はアクションを起こした時点でいなくなるので、二度目からアクセスが拒否される。


リクエストを投げていない場合でも、全てのチェックボックスをONにするJavaScriptが一度動いたあと(submitはしない)、そのままの画面でチェックボックスをクリックしたりしただけでもエラーとなるのは何故なのでしょうか。。

質問ばかりで申し訳ありません。
よろしくお願いいたします。
すみょし
常連さん
会議室デビュー日: 2007/01/25
投稿数: 36
投稿日時: 2007-03-29 09:08
おはようございます。

>ページ遷移を行わないように、xml内のフォワード先、リダイレクト先をnullにしており、
>ファイルをブラウザに返しているだけで、ページ遷移は行われないはずです。

とありますので、フォワード先、リダイレクト先をnull指定するのではなく、
そもそもsendRedirect、forwardしてはいけません。

Scriptが一度実行した後、CSVダウンロードを行うと、Servlet中で遷移先がnull設定されていようと、
sendRedirect、forwardいずれかが必ず実行されているので、どうやらCSVダウンロード実行前と実行後で別window(フレーム)と解釈されているような気がします。
とりあえず、sendRedirectとforwardを行わないようにしてから実行してみていただけますか?
もちろんサイズ0のiframeそのままでお願いします。
maki
会議室デビュー日: 2007/03/13
投稿数: 7
お住まい・勤務地: 大阪府
投稿日時: 2007-03-29 11:13
すみょしさん、おはようございます。
返答ありがとうございます。

引用:

>ページ遷移を行わないように、xml内のフォワード先、リダイレクト先をnullにしており、
>ファイルをブラウザに返しているだけで、ページ遷移は行われないはずです。
とありますので、フォワード先、リダイレクト先をnull指定するのではなく、
そもそもsendRedirect、forwardしてはいけません。


=====================================================================
if (pageForward != null) {        ←pageForward=nullなのでforwardしない
// ForwardページへForward
RequestDispatcher dispatcher = servletContext.getRequestDispatcher(pageForward);
dispatcher.forward(condition.getHttpServletRequest(), condition.getHttpServletResponse());
} else if (pageRedirect != null) {   ←pageRedirect=nullなのでredirectしない
// RedirectパスへRedirect
pageRedirect = condition.getHttpServletResponse().encodeRedirectURL(UrlRedirectUtil.getSendRedirectPath(pageRedirect));
condition.getHttpServletResponse().sendRedirect(pageRedirect);
}
=====================================================================
コード上、null指定した場合は、if文の中もelseifの中も通らないので、sendRedirect、forward自体を行っていないと思います。
(Forwardする前とRedirectする前にログ出力を行うコードを追加し、ログ出力されていないことで、if文、elseif文の中を通っていないことを確認済み)

sendRedirect、forwardしていない状態でサイズ0のiframeをターゲット指定しリクエストしていますが動作は変わらないようです。

現在別の人間が社外の運用サーバで動作確認中なのですが、運用サーバでのみ確認できる現象で(私がいる社内ではIE6.0が無いため現象を確認できず)、他にも運用サーバではIEの挙動がおかしい現象が起こっているので(セキュリティの設定は既定の中低にしているそうですが、セキュリティ警告のポップアップがやたら表示されるなど)IEが不安定なのかなと思っています。。
とりあえず、IE6.0SP2にバージョンを上げてもらって再度動作確認をしてもらおうと思います。

[ メッセージ編集済み 編集者: maki 編集日時 2007-03-29 11:16 ]

スキルアップ/キャリアアップ(JOB@IT)