NIFCLOUD-mbaas / UserCommunity

ニフクラ mobile backend ユーザーコミュニティ
https://mbaas.nifcloud.com/
81 stars 18 forks source link

pythonでデータストアの値を取得できたが、取得数を変えることができない #1043

Closed miyagin15 closed 5 years ago

miyagin15 commented 5 years ago

データストアにpythonでアクセスすることがでてき、100件のデータを取得することができました.

limitを設定して取得数を変えようとしているのですが、うまくできません。 現在

req = urllib.request.Request("https://mbaas.api.nifcloud.com/2013-09-01/classes/*クラス名*/", headers=headers)

として取得ができています。 しかし

req = urllib.request.Request("https://mbaas.api.nifcloud.com/2013-09-01/classes/*クラス名*&limit=100", headers=headers)

とすると403 Forbiddenが返ってきます。 リクエストするURLが間違っているのでしょうか?

ちなみに REST APIツールのほうでクエリにlimit =100を設定したときのsignatureをheaderに設定しています

goofmint commented 5 years ago

他のパラメータが分かりませんが、

req = urllib.request.Request("https://mbaas.api.nifcloud.com/2013-09-01/classes/*クラス名*&limit=100", headers=headers)

ではなくて、

req = urllib.request.Request("https://mbaas.api.nifcloud.com/2013-09-01/classes/*クラス名*?limit=100", headers=headers)

ということはないでしょうか? & ではなく ? です。

miyagin15 commented 5 years ago

迅速な回答ありがとうございます。

?limit=100としても HTTPError: HTTP Error 403: Forbidden というレスポンスになってしまいます。

headersは

headers = {
    "X-NCMB-Application-Key" :"***",
    "X-NCMB-Timestamp" :"***",
    "X-NCMB-Signature" :"***",
    "Content-Type" :"application/json"
}

上のようにしていて "X-NCMB-Signature" :"***"の値はニフクラREST APIツールのX-NCMB-Signatureを随時コピペしています limit数をいろいろ変えるたびにX-NCMB-Signatureの値が変わるため、 X-NCMB-Signatureはコピペしていますが エラーは変わりません。

goofmint commented 5 years ago

X-NCMB-Timestamp の値も変わっていますよね?署名の生成時にタイムスタンプも使っているので、アクセス時間が変わると署名も変わります。

REST APIツールのリクエスト部分をターミナルで実行して、そのまま結果が得られるならば、それをPython風にするだけで良いのですが。

Screenshot_ 2019-08-18 11 35 34
miyagin15 commented 5 years ago

以前使ってたプリセットを使ってるためか、X-NCMB-Timestampは変わっていませんでした。 新しくプリセットを作り、X-NCMB-Timestampも更新した状態で、pythonで動かしてみたのですが、

import urllib.request, urllib.parse
headers = {
    "X-NCMB-Application-Key" :"****",
    "X-NCMB-Timestamp" :"2019-08-18***",
    "X-NCMB-Signature" :"***",
    "Content-Type" :"application/json"
}
req = urllib.request.Request("https://mbaas.api.nifcloud.com/2013-09-01/classes/No_Login?limit=1000", headers=headers)
with urllib.request.urlopen(req) as res:
    html = res.read().decode("utf-8")
    print(html)

としていますが、
HTTPError: HTTP Error 403: Forbiddenが返ってきます
REST APIツールのほうを実行すると値が返ってくるのは確認しています。
またそのREST APIツールとheaderの値は同じことは確認しました

~~~~~~~~~~~~~~~
 --data-urlencode 'limit=1000' \
https://mbaas.api.nifcloud.com/2013-09-01/classes/No_Login/

APIツールのほうと違うのはlimitがURLに入ってるか入ってないかぐらいかと思います。 limitを書かなければ100個データが取れるのは確認しています

何か考えられる原因はありますでしょうか?

goofmint commented 5 years ago

limit=100 というパラメータが入れば、署名の文字列も変わってきます。その署名はlimitが書かれていない場合の署名です。

署名はクエリストリングやタイムスタンプなどによって異なるものが生成されます。

miyagin15 commented 5 years ago

REST API ツール上でlimit数を変えたら署名の文字列をpythonにコピペしています。

わたしがやっていることは REST API ツールのほうでlimit数を変えたら、その都度、署名の文字列をコピーして

import urllib.request, urllib.parse
headers = {
    "X-NCMB-Application-Key" :"****",
    "X-NCMB-Timestamp" :"2019-08-18***",
    "X-NCMB-Signature" :"*ここ*",
    "Content-Type" :"application/json"
}
req = urllib.request.Request("https://mbaas.api.nifcloud.com/2013-09-01/classes/No_Login?limit=1000", headers=headers)
with urllib.request.urlopen(req) as res:
    html = res.read().decode("utf-8")
    print(html)

ここの署名にいれています。 ここでlimi数を150とか2000とか変えたときに、REST API ツールのほうでもlimit数を同じように変えて、署名の文字列が変わったのを確認してpythonにコピペしています。

limitがなしのときも同様にREST APIツールのほうでlimitを消して署名の文字列をコピーして

import urllib.request, urllib.parse
headers = {
    "X-NCMB-Application-Key" :"****",
    "X-NCMB-Timestamp" :"2019-08-18***",
    "X-NCMB-Signature" :"*ここ*",
    "Content-Type" :"application/json"
}
req = urllib.request.Request("https://mbaas.api.nifcloud.com/2013-09-01/classes/No_Login/", headers=headers)
with urllib.request.urlopen(req) as res:
    html = res.read().decode("utf-8")
    print(html)

としています。 これは予想通りに動くのですが、、

goofmint commented 5 years ago

X-NCMB-Timestamp の値も書き換えていますか?

miyagin15 commented 5 years ago

はい書き換えています。

個人的に、urlが間違っているのかと思っています。 クエリパラメータをつけない場合はうまくデータが取れるので

 --data-urlencode 'limit=1000' \

ここをうまくURLエンコードできていないのかと。

新しく

params = {
    'limit':1000,
}
params = {
    'limit':1000,
}
url="https://mbaas.api.nifcloud.com/2013-09-01/classes/No_Login"
req = urllib.request.Request("{}?{}".format(url, urllib.parse.urlencode(params)),headers=headers)
with urllib.request.urlopen(req) as res:
    html = res.read().decode("utf-8")
    print(html)

としてもHTTP Error 403: Forbiddenとなります

'{}?{}'.format(url, urllib.parse.urlencode(params),headers=headers))を出力すると 'https://mbaas.api.nifcloud.com/2013-09-01/classes/No_Login?limit=1000' となりあっているはずなのですが。

goofmint commented 5 years ago

https://qiita.com/hurutoriya/items/7156874ed2256c06a514

を見ると、渡し方が違うと言うことはないでしょうか?クエリストリングなので合っているように思うのですが。後、Pythonのコードに変換せず、curlコマンドそのまま実行した時には意図した結果が返ってくるのでしょうか。もし返ってくるならば、署名の問題ではないように思います。

goofmint commented 5 years ago

書かれているコードを試してみた限りでは、 https://mbaas.api.nifcloud.com/2013-09-01/classes/Example?limit=1000 で取得できます。書き換えたのは X-NCMB-Signature の値とURLです。REST APIツールで取れる値です。

違いはURLと署名だけのはずです。

limitなし版

import urllib.request, urllib.parse
headers = {
    "X-NCMB-Application-Key" :"b347bafb25296ae896e06684068574f4332e2526626f78b475e799ca5882901e",
    "X-NCMB-Timestamp" :"2019-08-20T02:42:44.659Z",
    "X-NCMB-Signature" :"KGKUqHxHW3XuVSSC/YDb4UZEJx9DLQQ0G0nAjGwpXSA=",
    "Content-Type" :"application/json"
}
req = urllib.request.Request("https://mbaas.api.nifcloud.com/2013-09-01/classes/Example", headers=headers)
with urllib.request.urlopen(req) as res:
    html = res.read().decode("utf-8")
    print(html)

limitあり版

import urllib.request, urllib.parse
headers = {
    "X-NCMB-Application-Key" :"b347bafb25296ae896e06684068574f4332e2526626f78b475e799ca5882901e",
    "X-NCMB-Timestamp" :"2019-08-20T02:42:44.659Z",
    "X-NCMB-Signature" :"yZF24KzAo3Y2gO1eyiAmTUjmo1tIwplTnOi72vtiD74=",
    "Content-Type" :"application/json"
}
req = urllib.request.Request("https://mbaas.api.nifcloud.com/2013-09-01/classes/Example?limit=1000", headers=headers)
with urllib.request.urlopen(req) as res:
    html = res.read().decode("utf-8")
    print(html)
miyagin15 commented 5 years ago

pythonで試していただいてありがとうございます。

req = urllib.request.Request("https://mbaas.api.nifcloud.com/2013-09-01/classes/No_Login/?limit=1000", headers=headers) とすることで値が取得できました クラス名の後に/?limit=1000としました。 なぜこうすることで取得できるようになったのかはわかりません。 もしなにかご存じでしたら教えてください。

何回も質問をしてしまってお手数をおかけしました。助かりました。