Home Php C# Sql C C++ Javascript Python Java Go Android Git Linux Asp.net Django .net Node.js Ios Xcode Cocoa Iphone Mysql Tomcat Mongodb Bash Objective-c Scala Visual-studio Apache Elasticsearch Jar Eclipse Jquery Ruby-on-rails Ruby Rubygems Android-studio Spring Lua Sqlite Emacs Ubuntu Perl Docker Swift Amazon-web-services Svn Html Ajax Xml Java-ee Maven Intellij-idea Rvm Macos Unix Css Ipad Postgresql Css3 Json Windows-server Vue.js Typescript Oracle Hibernate Internet-explorer Github Tensorflow Laravel Symfony Redis Html5 Google-app-engine Nginx Firefox Sqlalchemy Lucene Erlang Flask Vim Solr Webview Facebook Zend-framework Virtualenv Nosql Ide Twitter Safari Flutter Bundle Phonegap Centos Sphinx Actionscript Tornado Register | Login | Edit Tags | New Questions | 繁体 | 简体


10 questions online user: 47

0
votes
answers
53 views
+10

如何重命名數據存儲實體字段,但能夠通過舊的和新的屬性名稱檢索記錄?

0

我有一個實體如何重命名數據存儲實體字段,但能夠通過舊的和新的屬性名稱檢索記錄?

class Foo { 
    public String bar; 
} 

我想重命名 「酒吧」 到 「somethingElse」。並計劃使用Objectify的@AlsoLoad註解來實現這一點(我已經在使用Objectify進行持久化)。因此,像:

class Foo { 
    @AlsoLoad("bar") 
    public String somethingElse; 
} 

但形式有任何疑問:

final Query<Foo> query = OfyService.ofy().load().type(Foo.class) 
    .filter("somethingElse", "someValue"); 

只擷取自重命名已保存的實體。任何較舊的實體都被忽略。

什麼是重命名實體字段的最佳做法,以便我可以有一個將返回所有記錄的單個查詢?

沙发
0
3

注意:我不是一個客觀化的用戶,答案是通用的,所以你必須適應物化的細節。

一般要避免同時使用barsomethingElse爲長時間,主要是因爲尋找匹配實體轉化爲OR類型的查詢 - .filter("bar", "someValue")OR.filter("somethingElse", "someValue"),這是由數據存儲不支持的根本。從Restrictions on queries

NOTOR!=運營商本身不支持, 但有些客戶端庫可以在雲存儲上添加支持。

這意味着,在最好的,你必須跳火圈,使這樣的工作,例如見,Google Datastore combine (union) multiple sets of entity results to achieve OR condition

我的建議是進行一次性遷移,並用它完成。這將包括以下步驟:

  • 最有可能的,你必須有在遷移過程中性能配置/活着,所以不只是重命名bar,而不是添加somethingElse不要立即刪除bar
  • 在所有的地方,你更新bar屬性還更新somethingElse相應
  • 添加邏輯來查詢具有bar但沒有somethingElse並把它們重新寫那麼他們也有所有實體3210。這一步完成後,所有的實體應該有一個somethingElse鏡像bar在你讀bar的價值交換閱讀somethingElse代替
  • 檢查含somethingElse所有索引服務於所有非查詢的地方
  • ,然後換你的查詢從barsomethingElse。有了這個實際的遷移已完成,您可以執行以下
  • 降清理步驟寫bar財產
  • 執行查詢對具有bar屬性的所有entitites並把它們重新寫不bar。請注意,這可能比真正從模型和指標讓這些實體單獨
  • 下降bar(如果適用於您的客戶端庫)更貴,但只有當你在上一步中刪除了所有的實體財產

此方法的遷移可以緩慢執行,因爲它不需要完全關閉服務,因此可以通過live進行遷移。

+0

謝謝丹。我得出了同樣的結論。 – William

0
votes
answers
33 views
+10

在應用程序引擎項目中創建文件

-2

我想爲每個擁有用戶標識的用戶創建json文件。例如數據文件夾中的123456.json。當我剛剛在簡單的測試文件試試這個沒有燒瓶服務器工作原理:在應用程序引擎項目中創建文件

with open('data/3456789.json', "w+") as f: 
    print("test") 

,但是當我在燒瓶服務器調用它的應用程序引擎創建我收到錯誤No such file or directory: 'data/3456789.json' 這就是我main.py看起來像:

import os, sys 
from flask import Flask 
app = Flask(__name__) 

@app.route('/webhook', methods=['GET']) 
def createFile(): 
    with open('data/3456789.json', "w+") as f: 
    print("test") 
return "Welcome" 

if __name__ == '__main__': 
    port = int(os.getenv('PORT', 5000)) 
    print("Starting app on port %d" % port) 
    app.run(debug=False, port=port, host='0.0.0.0') 

main.py wokrs完美在我自己的電腦。沒有任何錯誤。任何想法?

沙发
0
1

應用程序引擎不會讓您部署的應用程序寫入文件系統。這是應用引擎沙箱的一部分。

但是,您可以從文件系統讀取數據。如果您可以在個人電腦上創建json文件,則可以將它們與您的應用程序一起部署,並且您的應用程序將能夠讀取這些文件。

+0

是的,你是對的。謝謝 :) – MRustamzade

6
votes
answers
24 views
+10

Google App Engine low memcache performance

Memcache is one of those things where the solution could be absolutely anything, and no one ever really gives a decent answer, maybe because there is none. So I'm not looking for a direct answer, but maybe just something to get me going in the right direction.

For a typical request, here is my AppStats info:

enter image description here

So, out of a total 440 ms request, I spend 342 ms in memcache. And here I figured memcache was supposed to be lightning fast. I must be doing something wrong.

Looking at my memcache statistics in my admin console, I have this:

Hit count:  3848
Miss count: 21382
Hit ratio:  15%

I'm no expert on this stuff, but I'm pretty sure 15% is terrible.

The typical request above is a bit too detailed to explain, but basically, I create and put a new entity, which also updates and puts a parent entity, which also updates and puts any users associated with the parent entity.

Throughout all this, I always get by key, never query. Oh and I'm using NDB, so all the basic memcache stuff is handled automatically. So I never actually touch memcache manually on my own in my code.

Any ideas?

Edit: Here is the breakdown of my request

enter image description here

So I only have 2 datastore gets and 2 puts. The rest is automatically handled memcache stuff. Why is it doing so much work? Would I be better off handling this stuff manually?

沙发
+60
+50

讓我們仔細看看你的數據。七個memcache寫入花費了兩個數據存儲區寫入的時間。這實際上證明了memcache比數據存儲快3.5倍。

如果對您的應用程序的典型請求需要更新至少三個數據庫實體 - 然後更新更多實體(關聯的用戶),則無法使此操作“快速閃電”。當您以比編寫條目更頻繁的方式閱讀條目時,Memcache會有所幫助。如果對用戶記錄的讀取和寫入量相同,則應考慮為此模型關閉緩存

您還可以嘗試異步操作任務隊列根據您的描述,您似乎首先嘗試更新實體,並在更新完成後更新其父實體,因為它很自然。你可以同時運行這些; 這可能需要一些重構,但這是值得的。

其次,可能更新“所有相關用戶”。推遲到後台產生的任務; 任務隊列有一個非常方便的接口。“關聯用戶”不會立即更新,但他們可能不需要!但是,您的請求的延遲將會少於。

所以你有點說,鑑於我經常更新實體,這是memcache的預期行為?我盡可能使用異步操作。我還沒有考慮任務隊列,但這似乎是一個好主意。 - 雪人10月30日在20:15

@mohabitar我對AppEngine的體驗是,每個系統調用都可以以非零概率“尖峰”(例如,從通常的10ms到50ms)。因此,您調用的RPC調用越多,其中一個調用的可能性就越大,並且會給您帶來更高的延遲。如果在每次訪問時更新內存緩存和數據存儲,則可能會為操作帶來更高的峰值風險。如果在兩次寫入之間,您有許多在memcache級別解析的讀取,則此風險可能是合理的。如果你不這樣做,你可能會更好,沒有緩存。 - P Shved 12年10月30日在20:48

18
votes
answers
40 views
+10

Google App Engine - Secure Cookies

I'd been searching for a way to do cookie based authentication/sessions in Google App Engine because I don't like the idea of memcache based sessions, and I also don't like the idea of forcing users to create google accounts just to use a website. I stumbled across someone's posting that mentioned some signed cookie functions from the Tornado framework and it looks like what I need. What I have in mind is storing a user's id in a tamper proof cookie, and maybe using a decorator for the request handlers to test the authentication status of the user, and as a side benefit the user id will be available to the request handler for datastore work and such. The concept would be similar to forms authentication in ASP.NET. This code comes from the web.py module of the Tornado framework.

According to the docstrings, it "Signs and timestamps a cookie so it cannot be forged" and "Returns the given signed cookie if it validates, or None."

I've tried to use it in an App Engine Project, but I don't understand the nuances of trying to get these methods to work in the context of the request handler. Can someone show me the right way to do this without losing the functionality that the FriendFeed developers put into it? The set_secure_cookie, and get_secure_cookie portions are the most important, but it would be nice to be able to use the other methods as well.

#!/usr/bin/env python

import Cookie
import base64
import time
import hashlib
import hmac
import datetime
import re
import calendar
import email.utils
import logging

def _utf8(s):
    if isinstance(s, unicode):
        return s.encode("utf-8")
    assert isinstance(s, str)
    return s

def _unicode(s):
    if isinstance(s, str):
        try:
            return s.decode("utf-8")
        except UnicodeDecodeError:
            raise HTTPError(400, "Non-utf8 argument")
    assert isinstance(s, unicode)
    return s 

def _time_independent_equals(a, b):
    if len(a) != len(b):
        return False
    result = 0
    for x, y in zip(a, b):
        result |= ord(x) ^ ord(y)
    return result == 0

def cookies(self):
    """A dictionary of Cookie.Morsel objects."""
    if not hasattr(self,"_cookies"):
        self._cookies = Cookie.BaseCookie()
        if "Cookie" in self.request.headers:
            try:
                self._cookies.load(self.request.headers["Cookie"])
            except:
                self.clear_all_cookies()
    return self._cookies

def _cookie_signature(self,*parts):
    self.require_setting("cookie_secret","secure cookies")
    hash = hmac.new(self.application.settings["cookie_secret"],
                    digestmod=hashlib.sha1)
    for part in parts:hash.update(part)
    return hash.hexdigest()

def get_cookie(self,name,default=None):
    """Gets the value of the cookie with the given name,else default."""
    if name in self.cookies:
        return self.cookies[name].value
    return default

def set_cookie(self,name,value,domain=None,expires=None,path="/",
               expires_days=None):
    """Sets the given cookie name/value with the given options."""
    name = _utf8(name)
    value = _utf8(value)
    if re.search(r"[x00-x20]",name + value):
        # Don't let us accidentally inject bad stuff
        raise ValueError("Invalid cookie %r:%r" % (name,value))
    if not hasattr(self,"_new_cookies"):
        self._new_cookies = []
    new_cookie = Cookie.BaseCookie()
    self._new_cookies.append(new_cookie)
    new_cookie[name] = value
    if domain:
        new_cookie[name]["domain"] = domain
    if expires_days is not None and not expires:
        expires = datetime.datetime.utcnow() + datetime.timedelta(
            days=expires_days)
    if expires:
        timestamp = calendar.timegm(expires.utctimetuple())
        new_cookie[name]["expires"] = email.utils.formatdate(
            timestamp,localtime=False,usegmt=True)
    if path:
        new_cookie[name]["path"] = path

def clear_cookie(self,name,path="/",domain=None):
    """Deletes the cookie with the given name."""
    expires = datetime.datetime.utcnow() - datetime.timedelta(days=365)
    self.set_cookie(name,value="",path=path,expires=expires,
                    domain=domain)

def clear_all_cookies(self):
    """Deletes all the cookies the user sent with this request."""
    for name in self.cookies.iterkeys():
        self.clear_cookie(name)

def set_secure_cookie(self,name,value,expires_days=30,**kwargs):
    """Signs and timestamps a cookie so it cannot be forged"""
    timestamp = str(int(time.time()))
    value = base64.b64encode(value)
    signature = self._cookie_signature(name,value,timestamp)
    value = "|".join([value,timestamp,signature])
    self.set_cookie(name,value,expires_days=expires_days,**kwargs)

def get_secure_cookie(self,name,include_name=True,value=None):
    """Returns the given signed cookie if it validates,or None"""
    if value is None:value = self.get_cookie(name)
    if not value:return None
    parts = value.split("|")
    if len(parts) != 3:return None
    if include_name:
        signature = self._cookie_signature(name,parts[0],parts[1])
    else:
        signature = self._cookie_signature(parts[0],parts[1])
    if not _time_independent_equals(parts[2],signature):
        logging.warning("Invalid cookie signature %r",value)
        return None
    timestamp = int(parts[1])
    if timestamp < time.time() - 31 * 86400:
        logging.warning("Expired cookie %r",value)
        return None
    try:
        return base64.b64decode(parts[0])
    except:
        return None

uid=1234|1234567890|d32b9e9c67274fa062e2599fd659cc14

Parts:
1. uid is the name of the key
2. 1234 is your value in clear
3. 1234567890 is the timestamp
4. d32b9e9c67274fa062e2599fd659cc14 is the signature made from the value and the timestamp

+120

Tornado was never meant to work with App Engine (it's "its own server" through and through). Why don't you pick instead some framework that was meant for App Engine from the word "go" and is lightweight and dandy, such as tipfy? It gives you authentication using its own user system or any of App Engine's own users, OpenIn, OAuth, and Facebook; sessions with secure cookies or GAE datastore; and much more besides, all in a superbly lightweight "non-framework" approach based on WSGI and Werkzeug. What's not to like?!

我不打算將Tornado與App Engine一起使用,我只想按照他們的方式設置和獲取已簽名的cookie。我看了一下tipfy / werkzeug安全cookie代碼,我認為他們在Tornado做的事情更優雅。 - tponthieux 2010年3月28日8:52

+30

For those who are still looking, we've extracted just the Tornado cookie implementation that you can use with App Engine at ThriveSmart. We're using it successfully on App Engine and will continue to keep it updated.

The cookie library itself is at: http://github.com/thrivesmart/prayls/blob/master/prayls/lilcookies.py

You can see it in action in our example app that's included. If the structure of our repository ever changes, you can look for lilcookes.py within github.com/thrivesmart/prayls

I hope that's helpful to someone out there!

地板
+30
+50

This works if anyone is interested:

from google.appengine.ext import webapp

import Cookie
import base64
import time
import hashlib
import hmac
import datetime
import re
import calendar
import email.utils
import logging

def _utf8(s):
    if isinstance(s, unicode):
        return s.encode("utf-8")
    assert isinstance(s, str)
    return s

def _unicode(s):
    if isinstance(s, str):
        try:
            return s.decode("utf-8")
        except UnicodeDecodeError:
            raise HTTPError(400, "Non-utf8 argument")
    assert isinstance(s, unicode)
    return s 

def _time_independent_equals(a, b):
    if len(a) != len(b):
        return False
    result = 0
    for x, y in zip(a, b):
        result |= ord(x) ^ ord(y)
    return result == 0


class ExtendedRequestHandler(webapp.RequestHandler):
    """Extends the Google App Engine webapp.RequestHandler."""
    def clear_cookie(self,name,path="/",domain=None):
        """Deletes the cookie with the given name."""
        expires = datetime.datetime.utcnow() - datetime.timedelta(days=365)
        self.set_cookie(name,value="",path=path,expires=expires,
                        domain=domain)    

    def clear_all_cookies(self):
        """Deletes all the cookies the user sent with this request."""
        for name in self.cookies.iterkeys():
            self.clear_cookie(name)            

    def cookies(self):
        """A dictionary of Cookie.Morsel objects."""
        if not hasattr(self,"_cookies"):
            self._cookies = Cookie.BaseCookie()
            if "Cookie" in self.request.headers:
                try:
                    self._cookies.load(self.request.headers["Cookie"])
                except:
                    self.clear_all_cookies()
        return self._cookies

    def _cookie_signature(self,*parts):
        """Hashes a string based on a pass-phrase."""
        hash = hmac.new("MySecretPhrase",digestmod=hashlib.sha1)
        for part in parts:hash.update(part)
        return hash.hexdigest() 

    def get_cookie(self,name,default=None):
        """Gets the value of the cookie with the given name,else default."""
        if name in self.request.cookies:
            return self.request.cookies[name]
        return default

    def set_cookie(self,name,value,domain=None,expires=None,path="/",expires_days=None):
        """Sets the given cookie name/value with the given options."""
        name = _utf8(name)
        value = _utf8(value)
        if re.search(r"[x00-x20]",name + value): # Don't let us accidentally inject bad stuff
            raise ValueError("Invalid cookie %r:%r" % (name,value))
        new_cookie = Cookie.BaseCookie()
        new_cookie[name] = value
        if domain:
            new_cookie[name]["domain"] = domain
        if expires_days is not None and not expires:
            expires = datetime.datetime.utcnow() + datetime.timedelta(days=expires_days)
        if expires:
            timestamp = calendar.timegm(expires.utctimetuple())
            new_cookie[name]["expires"] = email.utils.formatdate(timestamp,localtime=False,usegmt=True)
        if path:
            new_cookie[name]["path"] = path
        for morsel in new_cookie.values():
            self.response.headers.add_header('Set-Cookie',morsel.OutputString(None))

    def set_secure_cookie(self,name,value,expires_days=30,**kwargs):
        """Signs and timestamps a cookie so it cannot be forged"""
        timestamp = str(int(time.time()))
        value = base64.b64encode(value)
        signature = self._cookie_signature(name,value,timestamp)
        value = "|".join([value,timestamp,signature])
        self.set_cookie(name,value,expires_days=expires_days,**kwargs)

    def get_secure_cookie(self,name,include_name=True,value=None):
        """Returns the given signed cookie if it validates,or None"""
        if value is None:value = self.get_cookie(name)
        if not value:return None
        parts = value.split("|")
        if len(parts) != 3:return None
        if include_name:
            signature = self._cookie_signature(name,parts[0],parts[1])
        else:
            signature = self._cookie_signature(parts[0],parts[1])
        if not _time_independent_equals(parts[2],signature):
            logging.warning("Invalid cookie signature %r",value)
            return None
        timestamp = int(parts[1])
        if timestamp < time.time() - 31 * 86400:
            logging.warning("Expired cookie %r",value)
            return None
        try:
            return base64.b64decode(parts[0])
        except:
            return None

It can be used like this:

class MyHandler(ExtendedRequestHandler):
    def get(self):
        self.set_cookie(name="MyCookie",value="NewValue",expires_days=10)
        self.set_secure_cookie(name="MySecureCookie",value="SecureValue",expires_days=10)

        value1 = self.get_cookie('MyCookie')
        value2 = self.get_secure_cookie('MySecureCookie')
0

If you only want to store the user's user ID in the cookie (presumably so you can look their record up in the datastore), you don't need 'secure' or tamper-proof cookies - you just need a namespace that's big enough to make guessing user IDs impractical - eg, GUIDs, or other random data.

One pre-made option for this, which uses the datastore for session storage, is Beaker. Alternately, you could handle this yourself with set-cookie/cookie headers, if you really just need to store their user ID.

將用戶的id存儲在cookie中不是問題,但這不是我所追求的全部。應用程序引擎GUID並不是不切實際的猜測,使用其他一些GUID來驗證用戶似乎比它的價值更麻煩。只要哈希算法運行得相當快,將用戶的id放在已簽名的cookie中就可以很好地解決問題。之前我曾多次看過Beaker並決定反對,因為它看起來不像我想要的。 - tponthieux 2010年3月28日22:09

我相信有人會看到這一點,並確切知道如何使Tornado的代碼工作。它在問題發布中顯示為脫離上下文,但代碼片段是Tornado請求處理程序的一部分。我嘗試擴展webapp請求處理程序,但我無法讓它工作。修復可能很簡單,但我需要有更多經驗的人來告訴我如何做到這一點。 - tponthieux 2010年3月28日22:11

我很好奇為什麼你如此決心使用Tornado的會話模塊?還有其他幾個很好的會話模塊,包括Beaker,它提供了一個只有cookie的簽名選項。 - 尼克約翰遜2010年3月29日9:13

0

Someone recently extracted the authentication and session code from Tornado and created a new library specifically for GAE.

Perhaps this is more then you need, but since they did it specifically for GAE you shouldn't have to worry about adapting it yourself.

Their library is called gaema. Here is their announcement in the GAE Python group on 4 Mar 2010: http://groups.google.com/group/google-appengine-python/browse_thread/thread/d2d6c597d66ecad3/06c6dc49cb8eca0c?lnk=gst&q=tornado#06c6dc49cb8eca0c

這很酷。webapp框架應該添加對第三方認證機制的支持,因為它似乎是一種流行的趨勢。以下是他們在gaema頁面上所說的內容“gaema僅對用戶進行身份驗證,並且不提供會話或安全cookie等持久性以保持用戶登錄..” - tponthieux 2010年3月29日6:31

0
votes
answers
49 views
+10

嘗試在本地Google AppEngine服務器上登錄時出現503錯誤

1

我有一個功能強大的Go應用程序,我一直在本地運行數月。使用Google Cloud進行設置,測試運行到實時域,一切正常。嘗試在本地Google AppEngine服務器上登錄時出現503錯誤

回頭看我的本地機器,我想運行一個local Google AppEngine server(而不是直接運行我的Go應用程序)。它運行,但是我試圖在app.yaml中使用「login:required」參數,並且我在localhost:8080上看到了登錄表單,但無論我輸入什麼電子郵件,它都會以503錯誤超時。

我的app.yaml:

application: myapp-dev 
env: flex 
runtime: go 
api_version: go1 

handlers: 
- url:/
    script: _go_app 
    login: required 

命令我用它來運行本地應用程序:

dev_appserver.py app.yaml 
+0

我遇到了運行Google未觸及的Hello World示例應用程序的相同問題。 :( –

沙发
0
0

靈活的環境不通過的app.yaml支持 '登錄' 功能(外部的任何定期登錄你會在你的應用程序中執行)。

標準環境的app.yaml文檔DOES名單 '登錄' 功能https://cloud.google.com/appengine/docs/standard/go/config/appref

靈活的環境app.yaml的文檔沒有列出 '登錄' 功能https://cloud.google.com/appengine/docs/flexible/go/configuring-your-app-with-app-yaml

但是更具體地說,頁面談論從Standard-to-Flex升級,提及用於flex的登錄處理程序已被棄用

https://cloud.google.com/appengine/docs/flexible/go/upgrading

下處理程序的登錄設置現在已經廢棄了App Engine的 靈活的環境。您應遵循用戶服務 遷移的指導。

所以基本上,在flex環境中,在您的應用程序之外沒有項目範圍的登錄控制。你必須讓應用初始化,然後進行正常的認證/授權。

對於我自己的項目,我想要一個快速的應用程序級別的安全性,以便我可以提供訪客帳戶並讓他們看到我的應用的公共未登錄視圖是什麼。是的,我可以在我的應用程序中做同樣的事情,我只想保存一些工作。

0
votes
answers
40 views
+10

如何使用Google App Engine中的特定關鍵字獲取結果在Java中使用NO-SQL數據存儲區查詢?

0

我們使用GoogleInfo表,在該表中,我們存儲了應用程序的範圍。例如「https://www.googleapis.com/auth/drive.appdata,https://www.googleapis.com/auth/drive.file」 ,並且我試圖根據某個關鍵字(例如範圍內的「drive」)獲取結果,並根據該關鍵字獲得結果。以下是我的代碼。請建議。如何使用Google App Engine中的特定關鍵字獲取結果在Java中使用NO-SQL數據存儲區查詢?

String keywords[] = {"admin","drive","gmail","userinfo"}; 

Query query = pm.newQuery("SELECT scopes FROM com.cloudcodes.gcontrol.dataaccesslayer.insights.google.drive.GoogleInfo where :p.contains(scopes)"); 

result = (List) query.execute(Arrays.asList(keywords)); 
List tempResult = new ArrayList(); 
tempResult.addAll(result); 
return tempResult; 
沙发
0
0

似乎你正在使用JDO [1]和PersistanceManager [2]。

就我所見,您嘗試執行的查詢可能是錯誤的。檢查如何使用JDO執行查詢[3]。

您所查詢的是:

String keywords[] = {"admin","drive","gmail","userinfo"}; 
Query query = pm.newQuery("SELECT scopes FROM com.cloudcodes.gcontrol.dataaccesslayer.insights.google.drive.GoogleInfo where :p.contains(scopes)"); 
result = (List) query.execute(Arrays.asList(keywords)); 

看起來你想要做的事,如:

//Query for all persons with lastName equal to Smith or Jones 
Query q = pm.newQuery(Person.class, ":p.contains(lastName)"); 
q.execute(Arrays.asList("Smith", "Jones")); 
Person.class is the kind 
Arrays.asList("Smith", "Jones") 

此參數 「:p.contains(lastName的)」 定義lastName的是我們想要的屬性檢查。 您正在將該類設置爲com.cloudcodes.gcontrol.dataaccesslayer.insights.google.drive.GoogleInfo,我想這是完整的Java名稱包,其中的類習慣是類名,而類名是GoogleInfo。所以你可以嘗試:

Query q = pm.newQuery(GoogleInfo.class, ":p.contains(scopes)"); 
q.execute(Arrays.asList("admin","drive","gmail","userinfo")); 

你想檢索範圍。我假設你想使用REST API。所以在裏面:p.contains(「scopes」)可能會去與您想要檢索的實體中的keyWords相關的另一個屬性,也許是數組屬性?

在這裏,我與大家分享一些可能有用的文檔[4] [5]。

希望這會有所幫助!

[1] https://cloud.google.com/appengine/docs/standard/java/datastore/jdo/overview-dn2

[2] http://massapi.com/method/javax/jdo/PersistenceManager.newQuery-4.html

[3] https://cloud.google.com/appengine/docs/standard/java/datastore/jdo/queries

[4] https://cloud.google.com/datastore/docs/concepts/overview#comparison_with_traditional_databases

[5] https://cloud.google.com/datastore/docs/reference/gql_reference

7
votes
answers
22 views
+10

Class JavaLaunchHelper is implemented in both. One of the two will be used. Which one is undefined [duplicate]

Have a simple Google App Engine Web Application Project on Eclipse Kepler on Mac OS X with java version "1.7.0_45"

Running into the following :

objc[5398]: Class JavaLaunchHelper is implemented in both /Library/Java/JavaVirtualMachines/jdk1.7.0_45.jdk/Contents/Home/bin/java and /Library/Java/JavaVirtualMachines/jdk1.7.0_45.jdk/Contents/Home/jre/lib/libinstrument.dylib. One of the two will be used. Which one is undefined.

when I try to run as web application on localhost

Possibly related to the following issue :

https://code.google.com/p/googleappengine/issues/detail?id=10046

Any help would be useful.

沙发
+70
  1. 從這里安裝Java 7u21: http://www.oracle.com/technetwork/java/javase/downloads/java-archive-downloads-javase7-521261.html#jdk-7u21-oth -JPR

  2. 設置這些變量:

      export JAVA_HOME =“/ Library / Java / JavaVirtualMachines / jdk1.7.0_21。 jdk / Contents / Home“導出PATH = $ JAVA_HOME / bin:$ PATH    
  3. 運行你的應用程序並開心:) < / ol>

    (次要更新:將變量值放在引號中)

5
votes
answers
22 views
+10

Google App Engine Memcache API Quotas

Google App Engine's documentation states that memcache calls will count towards a quota. Yet, when I click through, memcache quotas or cost is not listed. How can I find the new pricing changes?

沙发
+50
+50

您可以在應用儀表板中找到它

儀表板 - >主要 - >配額詳細信息 - > Memcache

是的,它還可以。雖然在那個視圖中你只看到過去24小時(最多)的消耗,但你並沒有真正的歷史記錄。 - Shivan Dragon 2011年11月29日10:36

@AndreiBodnarescu你可以自己創建一個歷史日誌,如果可以的話。;)順便說一句,我發現儀表板中有幾個圖表,我認為GAE只是為那些人統計歷史。 - Kjuly 11年11月29日11:37

是的,但如果你這樣做,你就會增加你的資源使用量,特別是如果你想擁有像控制台那樣的詳細輸出用於其他統計數據。如果你把它放在異步任務中,你可能會僥倖成功,但是你沒有實時記錄它。 - Shivan Dragon 2011年11月30日7:24

0
votes
answers
46 views
+10

跨源請求阻止 - 創建實體GAE數據存儲

0

我下面這個谷歌火力地堡教程:https://cloud.google.com/appengine/docs/standard/python/authenticating-users-firebase-appengine跨源請求阻止 - 創建實體GAE數據存儲

我在最後一部分地方增加了注到數據存儲,但是當我按下按鈕來添加筆記它不會做任何事情,並給我在Firefox Web控制檯中的以下錯誤:

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://backend-dot-i7643225firenotes.appspot.com/notes. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing). 

任何想法是什麼原因造成這種情況?我沒有觸及Google提供的代碼,但無論如何我都會加入它。它的其餘部分可以在這裏找到:

https://github.com/GoogleCloudPlatform/python-docs-samples/tree/master/appengine/standard/firebase/firenotes

main.js

// Copyright 2016, Google, Inc. 
// Licensed under the Apache License, Version 2.0 (the "License"); 
// you may not use this file except in compliance with the License. 
// You may obtain a copy of the License at 
// 
// http://www.apache.org/licenses/LICENSE-2.0 
// 
// Unless required by applicable law or agreed to in writing, software 
// distributed under the License is distributed on an "AS IS" BASIS, 
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
// See the License for the specific language governing permissions and 
// limitations under the License. 

$(function(){ 
    // This is the host for the backend. 
    // TODO: When running Firenotes locally, set to http://localhost:8081. Before 
    // deploying the application to a live production environment, change to 
    // https://backend-dot-<PROJECT_ID>.appspot.com as specified in the 
    // backend's app.yaml file. 
    var backendHostUrl = 'https://backend-dot-i7643225firenotes.appspot.com'; //localhost:8081 

    // Initialize Firebase 
    // TODO: Replace with your project's customized code snippet 
    var config = { 
    apiKey: "REMOVED", 
    authDomain: "REMOVED", 
    databaseURL: "https://<DATABASE_NAME>.firebaseio.com", 
    storageBucket: "<BUCKET>.appspot.com", 
    }; 

    // This is passed into the backend to authenticate the user. 
    var userIdToken = null; 

    // Firebase log-in 
    function configureFirebaseLogin() { 

    firebase.initializeApp(config); 

    // [START onAuthStateChanged] 
    firebase.auth().onAuthStateChanged(function(user) { 
     if (user) { 
     $('#logged-out').hide(); 
     var name = user.displayName; 

     /* If the provider gives a display name, use the name for the 
     personal welcome message. Otherwise, use the user's email. */ 
     var welcomeName = name ? name : user.email; 

     user.getToken().then(function(idToken) { 
      userIdToken = idToken; 

      /* Now that the user is authenicated, fetch the notes. */ 
      fetchNotes(); 

      $('#user').text(welcomeName); 
      $('#logged-in').show(); 

     }); 

     } else { 
     $('#logged-in').hide(); 
     $('#logged-out').show(); 

     } 
    // [END onAuthStateChanged] 

    }); 

    } 

    // [START configureFirebaseLoginWidget] 
    // Firebase log-in widget 
    function configureFirebaseLoginWidget() { 
    var uiConfig = { 
     'signInSuccessUrl': '/', 
     'signInOptions': [ 
     // Leave the lines as is for the providers you want to offer your users. 
     firebase.auth.GoogleAuthProvider.PROVIDER_ID, 

     //firebase.auth.FacebookAuthProvider.PROVIDER_ID, 
     //firebase.auth.TwitterAuthProvider.PROVIDER_ID, 
     //firebase.auth.GithubAuthProvider.PROVIDER_ID, 

     firebase.auth.EmailAuthProvider.PROVIDER_ID 
     ], 
     // Terms of service url 
     'tosUrl': '<your-tos-url>', 
    }; 

    var ui = new firebaseui.auth.AuthUI(firebase.auth()); 
    ui.start('#firebaseui-auth-container', uiConfig); 
    } 
    // [END configureFirebaseLoginWidget] 

    // [START fetchNotes] 
    // Fetch notes from the backend. 
    function fetchNotes() { 
    $.ajax(backendHostUrl + '/notes', { 
     /* Set header for the XMLHttpRequest to get data from the web server 
     associated with userIdToken */ 
     headers: { 
     'Authorization': 'Bearer ' + userIdToken 
     } 
    }).then(function(data){ 
     $('#notes-container').empty(); 
     // Iterate over user data to display user's notes from database. 
     data.forEach(function(note){ 
     $('#notes-container').append($('<p>').text(note.message)); 
     }); 
    }); 
    } 
    // [END fetchNotes] 

    // [START signOutBtn] 
    // Sign out a user 
    var signOutBtn =$('#sign-out'); 
    signOutBtn.click(function(event) { 
    event.preventDefault(); 

    //FirebaseAuth.getInstance().signOut(); 
    firebase.auth().signOut().then(function() { 
     console.log("Sign out successful"); 
    }, function(error) { 
     console.log(error); 
    }); 
    }); 
    // [END signOutBtn] 

    // [START saveNoteBtn] 
    // Save a note to the backend 
    var saveNoteBtn = $('#add-note'); 
    saveNoteBtn.click(function(event) { 
    event.preventDefault(); 

    var noteField = $('#note-content'); 
    var note = noteField.val(); 
    noteField.val(""); 

    /* Send note data to backend, storing in database with existing data 
    associated with userIdToken */ 
    $.ajax(backendHostUrl + '/notes', { 
     headers: { 
     'Authorization': 'Bearer ' + userIdToken 
     }, 
     method: 'POST', 
     data: JSON.stringify({'message': note}), 
     contentType : 'application/json' 
    }).then(function(){ 
     // Refresh notebook display. 
     fetchNotes(); 
    }); 

    }); 
    // [END saveNoteBtn] 

    configureFirebaseLogin(); 
    configureFirebaseLoginWidget(); 

}); 

main.py

# Copyright 2016 Google Inc. 
# 
# Licensed under the Apache License, Version 2.0 (the "License"); 
# you may not use this file except in compliance with the License. 
# You may obtain a copy of the License at 
# 
#  http://www.apache.org/licenses/LICENSE-2.0 
# 
# Unless required by applicable law or agreed to in writing, software 
# distributed under the License is distributed on an "AS IS" BASIS, 
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
# See the License for the specific language governing permissions and 
# limitations under the License. 

# [START app] 
import logging 

from flask import Flask, jsonify, request 
import flask_cors 
from google.appengine.ext import ndb 
import google.auth.transport.requests 
import google.oauth2.id_token 
import requests_toolbelt.adapters.appengine 

# Use the App Engine Requests adapter. This makes sure that Requests uses 
# URLFetch. 
requests_toolbelt.adapters.appengine.monkeypatch() 
HTTP_REQUEST = google.auth.transport.requests.Request() 

app = Flask(__name__) 
flask_cors.CORS(app) 


# [START note] 
class Note(ndb.Model): 
    """NDB model class for a user's note. 

    Key is user id from decrypted token. 
    """ 
    friendly_id = ndb.StringProperty() 
    message = ndb.TextProperty() 
    created = ndb.DateTimeProperty(auto_now_add=True) 
# [END note] 


# [START query_database] 
def query_database(user_id): 
    """Fetches all notes associated with user_id. 

    Notes are ordered them by date created, with most recent note added 
    first. 
    """ 
    ancestor_key = ndb.Key(Note, user_id) 
    query = Note.query(ancestor=ancestor_key).order(-Note.created) 
    notes = query.fetch() 

    note_messages = [] 

    for note in notes: 
     note_messages.append({ 
      'friendly_id': note.friendly_id, 
      'message': note.message, 
      'created': note.created 
     }) 

    return note_messages 
# [END query_database] 


# [START list_notes] 
@app.route('/notes', methods=['GET']) 
def list_notes(): 
    """Returns a list of notes added by the current Firebase user.""" 

    # Verify Firebase auth. 
    # [START verify_token] 
    id_token = request.headers['Authorization'].split(' ').pop() 
    claims = google.oauth2.id_token.verify_firebase_token(
     id_token, HTTP_REQUEST) 
    if not claims: 
     return 'Unauthorized', 401 
    # [END verify_token] 

    notes = query_database(claims['sub']) 

    return jsonify(notes) 
# [END list_notes] 


# [START add_note] 
@app.route('/notes', methods=['POST', 'PUT']) 
def add_note(): 
    """ 
    Adds a note to the user's notebook. The request should be in this format: 

     { 
      "message": "note message." 
     } 
    """ 

    # Verify Firebase auth. 
    id_token = request.headers['Authorization'].split(' ').pop() 
    claims = google.oauth2.id_token.verify_firebase_token(
     id_token, HTTP_REQUEST) 
    if not claims: 
     return 'Unauthorized', 401 

    # [START create_entity] 


    data = request.get_json() 

    # Populates note properties according to the model, 
    # with the user ID as the key name. 
    note = Note(
     parent=ndb.Key(Note, claims['sub']), 
     message=data['message']) 

    # Some providers do not provide one of these so either can be used. 
    note.friendly_id = claims.get('name', claims.get('email', 'Unknown')) 
    # [END create_entity] 

    # Stores note in database. 
    note.put() 

    return 'OK', 200 
# [END add_note] 


@app.errorhandler(500) 
def server_error(e): 
    # Log the error and stacktrace. 
    logging.exception('An error occurred during a request.') 
    return 'An internal error occurred.', 500 
# [END app] 
+0

.py文件中的CORS標頭在哪裏? – mplungjan

+0

我不確定這些是什麼?我需要包括這個嗎?這是谷歌自己的代碼,所以不知道爲什麼它不起作用。 – jb2003

沙发
0
1

我已經試過the tutorial自己,我的一切工作正常,所以我想你可能會跳過一些步驟,或者你有一些錯誤的配置。

唯一明顯的區別我你的榜樣和我之間看,有以下幾種,所以你可以嘗試對其進行修改,以看到您的問題是否得到解決:

  • 我看到一些import error在我的代碼,所以我將這一行werkzeug==0.12.2添加到backend/requirements.txt文件中,該文件包含將要安裝的庫。 werzeug庫的最新版本已將一些依賴關係移至嵌套文件夾,這是爲什麼某些導入失敗的原因(您可以閱讀更多here)。然後,刪除lib文件夾並重新運行該命令以安裝庫pip install -r requirements.txt -t lib。在進行此修改之前,我遇到了與您的問題相同的問題,在我的應用程序中單擊保存按鈕時沒有發生任何事情,但在更改後,它工作正常。
  • 我的frontend/main.js文件中的config變量有一些您已刪除的其他字段。我有以下的參數this guide,並要我的火力地堡控制檯,點擊全面添加火力地堡到你的Web應用程序按鈕,如下複製內容:

config變量frontend/main.js

var config = { 
    apiKey: "<API_KEY>", 
    authDomain: "<PROJECT_ID>.firebaseapp.com", 
    databaseURL: "https://<PROJECT_ID>.firebaseio.com", 
    projectId: "<PROJECT_ID>", 
    storageBucket: "<PROJECT_ID>.appspot.com", 
    messagingSenderId: "<SOME_ID>" 
    }; 

至於其他方面,一切看起來都很好,只是我剛剛嘗試過使用firebase.auth.GoogleAuthProvider.PROVIDER_ID,而我已經刪除了其餘所有內容。我也在運行生產中的應用程序(App Engine標準版),而不是使用本地的開發服務器。我看了一下我的CORS配置過了,我沒有什麼特別的,只有幾行,你已經在你的代碼:

app = Flask(__name__) 
flask_cors.CORS(app) 

你應該嘗試的情侶我提供建議,並與回來有關錯誤的更多信息,如果它不斷出現。

0
votes
answers
40 views
+10

App Engine PHP - dev_appserver工作,但appspot不

0

我的項目是一個基本的PHP網站,只有一點點的PHP包括頁眉/頁腳。App Engine PHP - dev_appserver工作,但appspot不

項目結構

  1. app.yaml駐留在根與/www目錄根也
  2. /www dir是所有PHP文件和目錄/www/assets
  3. /www/assets包含所有靜態文件。

配置文件

app.yaml文件被構造爲這樣:

runtime: php55 
api_version: 1 

handlers: 
- url:/
    script: www/index.php 

- url: /about.php 
    script: www/about.php 

- url: /(.*) 
    static_files: www/1 
    upload: www/(.*) 

關注,這是不太正確的。

我也需要任何其他的配置文件,如php.ini?或app.yaml將足夠?

問題

當我運行該項目在本地使用dev_appserver.py .它可以完美運行。

然而,當我使用gcloud app deploy部署項目中,我得到:

HTTP錯誤404,該頁面無法找到」。

沙发
0
0

您可能不希望匹配static_files中的www本身,因爲默認情況下表示該位置的.php文件不會被視爲應用程序文件。

您應該配置只是/www/assetsstatic_files(最後一個,到static_files URL模式不匹配),並從谷歌example保持推薦.php處理程序:

- url:/
    script: www/index.php 

# Serve php scripts. 
- url: /(.+.php)$ 
    script: www/1 

- url: /(.*) 
    static_files: www/assets/1 
    upload: www/assets/(.*) 

或者你可能能只需使用application_readable選項(Handlers element表中的第一行):

application_readable

可選。布爾。默認情況下,在靜態文件處理程序 中聲明的文件將作爲靜態數據上傳,並僅供最終用戶使用。他們 不能被應用程序讀取。如果此字段設置爲true,則 文件也將作爲代碼數據上傳,以便您的應用程序可以讀取它們的 。這兩種上傳都是針對您的代碼和靜態數據收取的 存儲resource quotas

像這樣:

- url:/
    script: www/index.php 

- url: /about.php 
    script: www/about.php 

- url: /(.*) 
    static_files: www/1 
    upload: www/(.*) 
    application_readable: true 

我個人認爲第一次的做法清潔。