8

POST と Content-Type application/xml を使用してオブジェクトを作成することに成功しました

また、Content-Type application/x-www-form-urlencoded を使用して、指定した URI に応じてすべてのオブジェクト タイプを返す空白のリクエスト ボディでクエリを実行することに成功しました。

リクエスト本文で PageNum=1&ResultsPerPage=1 のようなものを使用して同じことを行うこともできます。それを署名に組み込む方法を見つけたので、有効な応答が得られます。

ただし、どのようにフォーマットしても、フィルター (Filter=FAMILYNAME :EQUALS: Doe のような基本的なもの) を使用しようとすると、401 応答以外は得られません。[RFC3986] パーセント エンコーディングを使用してすべてのパラメータ名と値をエスケープする方法について、OAuth Core 1.0 Revision A の仕様を読みました。ただし、手順が不足しているか、フォーマットが間違っているように感じます。Intuit のフォーラムで正確に正しい形式を検索すると、一貫性のない情報が見つかりました。

これに関するヘルプは大歓迎です。私は今、良い週のためにこれに苦労してきました.

フィルターを使用しようとすると、次のような応答が返されます: HTTP Status 401 - message=Exception authenticationing OAuth; errorCode=003200; statusCode=401

- - アップデート - -

新しい IPP 開発者ツール - IPP API エクスプローラーでフィルターを使用しようとすると、同じエラーが表示されます。IDS V2 QBO API Explorer を使用しています。そのツールを使用してすべての投稿を取得でき、応答にはすべての顧客が表示されますが、フィルターを使用しようとすると、サーバー エラー 401 - 権限がありません: 資格情報が無効なため、アクセスが拒否されました。指定した資格情報を使用してこのディレクトリまたはページを表示する権限がありません。

何か案は?API Explorer ツールから同じエラーが発生した場合、問題はまったく別のものであると考えさせられます。

----最終更新----

私は最終的にフィルターで成功し、私の問題が何であるかを理解したと信じています. 「PageNum=1&ResultsPerPage=1」のようなページネーションを使用してクエリを実行できるのではないかと常に疑っていましたが、「Filter=FAMILYNAME :EQUALS: Doe」のようなクエリを取得できませんでした。フィルター形式の空白に問題があると思われました。以前にこれを追跡するのを思いとどまらせたのは、IDS V2 QBO API Explorer でフィルターを機能させることができなかったことです。それは私に何か他のことが起こっているのではないかと疑った. 私は、API Explorer をすべて無視して、一方の方法では機能するのに、他方の方法では機能しない理由に集中することにしました。

私の問題は、署名内のフィルターの値の不適切なエンコードに帰着したと思います。これは、私が受け取っていた 401 の無効な署名エラーを説明しています。

「Filter=Name :EQUALS: Doe」は、正規化すると「Filter=Name%20%3AEQUALS%20%3ADoe」になります。

「Filter%3DName%2520%253AEQUALS%2520%253ADoe」を与えるべきパーセントエンコーディング。

本質的に、空白とコロンを「二重」にエンコードする必要がありますが、等号はエンコードしません。エンコーディングを実行するために多くの順列を試しましたが、私の間違いは、「二重」エンコーディングではなかったか、二重エンコーディング中に「=」記号を含めていたことだと思います。いずれにせよ、あなたの署名を壊します。皆様のご意見をお寄せいただきありがとうございます。

4

3 に答える 3

2

私の問題は、署名内のフィルターの値の不適切なエンコードに帰着したと思います。これは、私が受け取っていた 401 の無効な署名エラーを説明しています。

オンライン ツールを使用して、Oauth リクエストに適切に署名するための手順を説明しました。これらの手順を進めているうちに、私の問題は、リクエスト パラメータを正規化してからパーセント エンコードする手順にあることに気付きました。正規化ステップでフィルターの「=」を含めていたため、署名が壊れていました。私が使用したツールは次の場所にあります。

http://hueniverse.com/2008/10/beginners-guide-to-oauth-part-iv-signing-requests/

皆様のご意見をお寄せいただきありがとうございます。

于 2013-02-21T17:54:30.113 に答える
1

API Explorer で同じリクエストを行っても 401 が返されますか?

http://ippblog.intuit.com/blog/2013/01/new-ipp-developer-tool-api-explorer.html

また、静的ベース URL を使用していますか、それとも実行時に取得していますか?

https://ipp.developer.intuit.com/0010_Intuit_Partner_Platform/0050_Data_Services/0400_QuickBooks_Online/0100_Calling_Data_Services/0010_Getting_the_Base_URL

静的ベース URL を使用している場合は、ランタイム ベース URL に切り替えて、引き続きエラーが発生するかどうかを確認してください。

于 2013-02-04T20:38:46.853 に答える
1

peterl は、ここで私の質問の 1 つに答えました。フィルターをヘッダーに入れる必要があるときに、フィルターを本文に入れようとしていました。以下は、特定の顧客のすべての未払いの請求書 (未払い残高が 0.00 より大きい) を取得するための peterl のコード サンプルです。

http://pastebin.com/raw.php?i=7VUB6whp

public List<Intuit.Ipp.Data.Qbo.Invoice> GetQboUnpaidInvoices(DataServices dataServices, int startPage, int resultsPerPage,  IdType CustomerId)
{
    StringBuilder requestXML = new StringBuilder();
    StringBuilder responseXML = new StringBuilder();

    var requestBody = String.Format("PageNum={0}&ResultsPerPage={1}&Filter=OpenBalance :GreaterThan: 0.00 :AND: CustomerId :EQUALS: {2}", startPage, resultsPerPage, CustomerId.Value);

    HttpWebRequest httpWebRequest = WebRequest.Create(dataServices.ServiceContext.BaseUrl + "invoices/v2/" + dataServices.ServiceContext.RealmId) as HttpWebRequest;
    httpWebRequest.Method = "POST";
    httpWebRequest.ContentType = "application/x-www-form-urlencoded";
    httpWebRequest.Headers.Add("Authorization", GetDevDefinedOAuthHeader(httpWebRequest, requestBody));
    requestXML.Append(requestBody);
    UTF8Encoding encoding = new UTF8Encoding();
    byte[] content = encoding.GetBytes(requestXML.ToString());
    using (var stream = httpWebRequest.GetRequestStream())
    {
        stream.Write(content, 0, content.Length);
    }
    HttpWebResponse httpWebResponse = httpWebRequest.GetResponse() as HttpWebResponse;
    using (Stream data = httpWebResponse.GetResponseStream())
    {
        Intuit.Ipp.Data.Qbo.SearchResults searchResults = (Intuit.Ipp.Data.Qbo.SearchResults)dataServices.ServiceContext.Serializer.Deserialize<Intuit.Ipp.Data.Qbo.SearchResults>(new StreamReader(data).ReadToEnd());
        return ((Intuit.Ipp.Data.Qbo.Invoices)searchResults.CdmCollections).Invoice.ToList();
    }

}

protected string GetDevDefinedOAuthHeader(HttpWebRequest webRequest, string requestBody)
{

    OAuthConsumerContext consumerContext = new OAuthConsumerContext
    {
        ConsumerKey = consumerKey,
        ConsumerSecret = consumerSecret,
        SignatureMethod = SignatureMethod.HmacSha1,
        UseHeaderForOAuthParameters = true

    };

    consumerContext.UseHeaderForOAuthParameters = true;

    //URIs not used - we already have Oauth tokens
    OAuthSession oSession = new OAuthSession(consumerContext, "https://www.example.com",
                            "https://www.example.com",
                            "https://www.example.com");


    oSession.AccessToken = new TokenBase
    {
        Token = accessToken,
        ConsumerKey = consumerKey,
        TokenSecret = accessTokenSecret
    };

    IConsumerRequest consumerRequest = oSession.Request();
    consumerRequest = ConsumerRequestExtensions.ForMethod(consumerRequest, webRequest.Method);
    consumerRequest = ConsumerRequestExtensions.ForUri(consumerRequest, webRequest.RequestUri);
    if (webRequest.Headers.Count > 0)
    {
        ConsumerRequestExtensions.AlterContext(consumerRequest, context => context.Headers = webRequest.Headers);
        if (webRequest.Headers[HttpRequestHeader.ContentType] == "application/x-www-form-urlencoded")
        {
            Dictionary<string, string> formParameters = new Dictionary<string, string>();
            foreach (string formParameter in requestBody.Split('&'))
            {
                formParameters.Add(formParameter.Split('=')[0], formParameter.Split('=')[1]);
            }
            consumerRequest = consumerRequest.WithFormParameters(formParameters);
        }
    }

    consumerRequest = consumerRequest.SignWithToken();
    return consumerRequest.Context.GenerateOAuthParametersForHeader();
}

元の質問を StackOverflow で見ることもできます: Query for All Invoices With Open Balances using QuickBooks Online (QBO) Intuit Partner Platform (IPP) DevKit

于 2013-02-21T13:27:51.190 に答える