質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

Ajax

Ajaxとは、Webブラウザ内で搭載されているJavaScriptのHTTP通信機能を使って非同期通信を利用し、インターフェイスの構築などを行う技術の総称です。XMLドキュメントを指定したURLから読み込み、画面描画やユーザの操作などと並行してサーバと非同期に通信するWebアプリケーションを実現することができます。

ASP.NET

ASP.NETは動的なWebサイトやWebアプリケーション、そしてWebサービスを構築出来るようにする為、Microsoftによって開発されたウェブアプリケーション開発フレームワークです。

VB.NET

Microsoft Visual Basic .NETのことで、Microsoft Visual Basic(VB6)の後継。 .NET環境向けのプログラムを開発することができます。 現在のVB.NETでは、.NET Frameworkを利用して開発を行うことが可能です。

Q&A

解決済

1回答

12698閲覧

AjaxからWCFサービスを呼び出すと、401エラーが出ます。

kurikurimaro

総合スコア9

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

Ajax

Ajaxとは、Webブラウザ内で搭載されているJavaScriptのHTTP通信機能を使って非同期通信を利用し、インターフェイスの構築などを行う技術の総称です。XMLドキュメントを指定したURLから読み込み、画面描画やユーザの操作などと並行してサーバと非同期に通信するWebアプリケーションを実現することができます。

ASP.NET

ASP.NETは動的なWebサイトやWebアプリケーション、そしてWebサービスを構築出来るようにする為、Microsoftによって開発されたウェブアプリケーション開発フレームワークです。

VB.NET

Microsoft Visual Basic .NETのことで、Microsoft Visual Basic(VB6)の後継。 .NET環境向けのプログラムを開発することができます。 現在のVB.NETでは、.NET Frameworkを利用して開発を行うことが可能です。

0グッド

0クリップ

投稿2016/12/21 02:09

編集2016/12/21 10:33

###前提・問題点
Microsof Visual Studio Community 2017で開発しております。
Windows 2012 ServerにWCFサービスを配置し、IISで公開しています。
'Access-Control-Allow-Origin'ヘッダが無いため401(Unauthorized)が返るとのことで、Ajaxから呼び出すことができません。
(下記ソースコードの、WCFサービスにおけるGlobal.asaxがうまく読み込めていないためかと考えているのですが、)どのように修正したらよいでしょうか。また、気をつけるべき設定はあるでしょうか。
なお、URLがドメインを含んでいるのは、Cordovaでモバイルアプリ化を図ろうとしているためです。クロスドメインでも呼び出せるようにGlobal.asaxファイルを設けました。
###エラーメッセージ
Chromeの開発ツールで確認すると、以下のようなメッセージが出ています。

  1. Failed to load resource:the server responded with a status of 401(Unauthorized)
  2. No 'Access-Control-Allow-Origin' header is present on the requested resource.

Chromeのエラーメッセージ
###ソースコード
呼出側のAjaxの抜粋です。

JAVASCRIPT

1 function SetselCate() { 2 var iData = {}; 3 iData.Cate = 1; 4 5 $.ajax({ 6 // url: '<%=ResolveUrl("~/SyouBu.svc/SetselCate")%>', //これは用いない 7 url: 'http://*********.jp/SHOPserv/SyouBu.svc/SetselCate', 8 type: 'GET', 9 dataType: 'json', 10 contentType: "application/json; charset=utf-8", 11 data: iData, 12 success: function (response) { 13 var cateset = JSON.parse(response.d); 14 $.each(cateset, function () { 15 var setCateID = this.cateid; 16 var setCateNM = this.catenm; 17 }); 18 }, 19 error: function (xhr, status, err) { 20 console.log(xhr); 21 console.log(status); 22 console.log(err); 23 alert('通信失敗'); 24 25 } 26 }); 27 };

WCFサービスです。ファイル名はWcfService1です。

VBNET

1Imports System.ServiceModel 2Imports System.ServiceModel.Activation 3Imports System.ServiceModel.Web 4Imports System.Web.Script.Serialization 5 6<ServiceContract(Namespace:="")> 7<AspNetCompatibilityRequirements(RequirementsMode:=AspNetCompatibilityRequirementsMode.Allowed)> 8Public Class SyouBu 9 <WebGet()> 10 Public Function SetselCate(ByVal Cate As String) As String 11 Dim syoubu As New List(Of Object)() 12 syoubu.Add(New With { 13 Key .cateid = "カテゴリIDの返り値", 14 Key .catenm = "カテゴリ名の返り値" 15 }) 16 Return (New JavaScriptSerializer().Serialize(syoubu)) 17 End Function 18End Class

WCFサービスのGlobal.asaxです。

VBNET

1Imports System.Web.SessionState 2 3Public Class Global_asax 4 Inherits System.Web.HttpApplication 5 Protected Sub Application_BeginRequest(sender As Object, e As EventArgs) 6 HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache) 7 HttpContext.Current.Response.Cache.SetNoStore() 8 EnableCrossDmainAjaxCall() 9 End Sub 10 11 Private Sub EnableCrossDmainAjaxCall() 12 HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*") 13 14 If HttpContext.Current.Request.HttpMethod = "OPTIONS" Then 15 HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST") 16 HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept") 17 HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000") 18 HttpContext.Current.Response.[End]() 19 End If 20 End Sub 21End Class

Web.configの一部です。

XML

1 <system.serviceModel> 2 <behaviors> 3 <endpointBehaviors> 4 <behavior name="WcfService1.SyouBuAspNetAjaxBehavior"> 5 <enableWebScript /> 6 </behavior> 7 </endpointBehaviors> 8 9 <serviceBehaviors> 10 <behavior name="ajaxServiceBehavior"> 11 <serviceDebug includeExceptionDetailInFaults="true" /> 12 </behavior> 13 <behavior name=""> 14 <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" /> 15 <serviceDebug includeExceptionDetailInFaults="false" /> 16 </behavior> 17 </serviceBehaviors> 18 </behaviors> 19 20 <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" /> 21 22 <services> 23 <service name="WcfService1.SyouBu"> 24 <endpoint address="" behaviorConfiguration="WcfService1.SyouBuAspNetAjaxBehavior" binding="webHttpBinding" contract="WcfService1.SyouBu" /> 25 </service> 26 </services> 27 28 </system.serviceModel>

###試したこと
同一ドメインであれば問題なく期待通りの結果が得られていると思います。
開発環境(Windows10)のIISにWCFサービスを配置して試したところ、エラーは出ませんでした。
ローカルのIPアドレスが192.168.0.108 なので、AjaxのURLを以下のように書きました。
url: 'http://192.168.0.108/SHOPserv/SyouBu.svc/SetselCate',

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2016/12/21 05:59

ブラウザは何ですか? Cross-Origin Resource Sharing をサポートしていますか? http://caniuse.com/#feat=cors  クロスドメインの対応が問題なだけで、同一ドメインであれば問題なく期待通りの結果が得られるのでしょうか?(開発環境でなら確認できますよね? 確認できてなければ確認してください) 
kurikurimaro

2016/12/21 09:34

ブラウザは、GoogleChromeです。FireFoxでも同様の結果となりました。
kurikurimaro

2016/12/21 09:35

「試したこと」を追記しました。同一ドメインであれば問題ないようです。
退会済みユーザー
kurikurimaro

2016/12/27 00:51

引用のリンクは、当該質問と比べて不要なファイルが含まれているもので、目的を達するためには良くない質問でした…。
退会済みユーザー

退会済みユーザー

2016/12/27 03:32

では、こちらで Q&A を続けるようお願いします。余計なお世話かもしれませんが、Stackoverflow の方はクローズした方がよさそうです。
退会済みユーザー

退会済みユーザー

2016/12/27 03:41

「比べて不要なファイルが含まれているもの」とのことですが、自分が検証用に使った WCF サービスも Visual Studio のインターネット用テンプレートを使ったもので、フォーム認証に必要なコードが入っている Account フォルダその他 WCF サービスには不要なファイルが山ほど含まれています。なので、本来は不要なファイルがあっても問題はないはずです。ちなみに自分が検証用に使った WCF サービスは http://surferonwww.info/BlogEngine/post/2015/10/15/wcf-and-jquery-ajax.aspx の通りです。これを不要なファイルが山ほどある既存の ASP.NET Web Forms アプリに追加しています。
kurikurimaro

2017/02/20 11:34

通常でも不要なファイルは多いのですね。引用のリンクのほうは、未だに問題の切り分けや原因はわからないのですが、とりあえず不要なのでクローズしておきました。
guest

回答1

0

ベストアンサー

レスが遅くなりました。

ブラウザのバージョンが不明ですが最新版で Cross-Origin Resource Sharing をサポートしていて、問題は Cross-Origin Resource Sharing を利用してのクロスドメインの対応がうまくいってないだけと理解してレスします。

原因として考えられるのは Global.asax に設定した EnableCrossDmainAjaxCall() メソッドが期待通り動いてなくて Cross-Origin Resource Sharing に必要なヘッダが WCF サービスからの応答に含まれないことぐらいです。

質問者さんの EnableCrossDmainAjaxCall() メソッドのコードは多分以下の記事からコピペして "http://localhost:5187" を "*" に書き換えたのだと思います。コードは正しいと思いますが、それがうまく動いてないように思われます。

Consuming WCF REST Services Using jQuery AJAX Calls
https://www.codeproject.com/kb/ajax/jquerywcfrest.aspx

それがうまく動いていて必要なヘッダがやり取りされているかを、ブラウザと WCF サービスの間の要求・応答を Fiddler 等のキャプチャツールでキャプチャして調べてみるのが原因究明のために良いと思います。

質問者さんの jQuery.ajax のコードを見ると contentType: "application/json; charset=utf-8" が含まれているので、以下の記事で言う「シンプルなリクエスト」にはならず、まず「プリフライトリクエスト」が行われてクロスドメインアクセスが可能か確認してから WCF サービスのメソッドにアクセスしてデータを取得するという動きになるはずです。

HTTP アクセス制御 (CORS)
https://developer.mozilla.org/ja/docs/Web/HTTP/HTTP_access_control

Fiddler で「プリフライトリクエスト」を見ると以下の画像ようになります。

http://surferonwww.info/BlogEngine/image.axd?picture=2016%2f12%2fCORS.jpg

Request Headers で赤枠で囲った部分に注目してください、ブラウザが Cross-Origin Resource Sharing をサポートしていれば、クロスドメイン要求でかつ「シンプルなリクエスト」にならない場合、自動的にこのような「プリフライトリクエスト」のためのヘッダを送信してくれます。(使ったブラウザは Firefox 50.1.0 です。Chrome は若干違いますが肝心の部分は同じになるはずです)

サーバーが要求を受けると EnableCrossDmainAjaxCall() によって応答ヘッダが返されるはずです。質問者さんのコードが期待通り動いていれば以下のようになるはずです。

Access-Control-Allow-Origin: * Access-Control-Allow-Methods: GET, POST Access-Control-Allow-Headers: Content-Type, Accept Access-Control-Max-Age: 1728000

(注)Access-Control-Max-Age の設定があると「プリフライトリクエスト」の結果がキャッシュされるので、その時間が経過するまでの同一リソースに対するアクセスに関しては、ブラウザは「プリフライトリクエスト」を発行せずに実際のリクエストを直接送るので注意してください。検証中は削除しておいた方がいいかもしれません。

この応答を受けてからブラウザは WCF サービスのメソッドにアクセスしてデータを取得します。上の Fiddler の画像の左側のウィンドウでハイライトした次の行がそれです。

その応答にも EnableCrossDmainAjaxCall() によってヘッダに Access-Control-Allow-Origin: * が含まれるはずです。

#ところで、質問者さんの jQuery.ajax のコードですが、GET 要求であれば contentType: "application/json; charset=utf-8" の設定は不要なはずです。それを削除すれば「シンプルなリクエスト」になって、「プリフライトリクエスト」はスキップして応答が返ってくるはずです。そのとき応答ヘッダに Access-Control-Allow-Origin: * が含まれていれば、エラーにならず期待通りの結果になると思います。

投稿2016/12/23 07:29

編集2016/12/23 13:23
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kurikurimaro

2016/12/27 00:55

丁寧な回答をありがとうございます。検証してみます。
Kurikurimaron

2017/01/29 07:46

>GET 要求であれば contentType: "application/json; charset=utf-8" の設定は不要 このことにより、目的が達成できました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問