具有云存储功能的Google App Engine无法在本地运行

时间:2016-06-21 19:02:45

标签: php wordpress google-app-engine google-cloud-storage

我在Google Appengine上运行Wordpress网站。它使用GAE插件进行wordpress。媒体库适用于appengine服务器,但不适用于本地服务器。大多数图像也是如此,除非它们具有硬编码链接。我收到了大量的404错误......

http://localhost:8080/_ah/gcs/<BUCKET_NAME>/image.png Failed to load resource: the server responded with a status of 404 (Not Found)

当gae服务器上的此链接工作时:

http://<BUCKET_NAME>.storage.googleapis.com/image.png

我在本地运行我的应用程序,如下所示: dev_appserver.py --php_executable_path=/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/php55/php-cgi .

似乎google的python脚本没有正确地将链接转发到真正的实际存储桶....任何想法?

2 个答案:

答案 0 :(得分:2)

这是预期的行为:

链接http://<BUCKET_NAME>.storage.googleapis.com/image.png是生产链接,请求从生产服务器提供。

链接http://localhost:8080/_ah/gcs/<BUCKET_NAME>/image.png是本地链接,devserver实际上必须包含<BUCKET_NAME>/image.png。该对象可能仅存储在生产中,当试图在本地机器上找到它时导致404。

作为一种解决方案,您可以考虑简单地针对生产云存储运行本地测试,以节省将所有存储项目传输(并保持同步)到本地的成本,这几乎肯定会在网络传输中花费更多和开发时间比这个更简单的替代方案。

答案 1 :(得分:0)

不确定这是否是同一个问题,但我发现来自dev_appserver.py的所有gcs请求都被路由到

http://localhost:8080/_ah/gcs/<BUCKET_NAME>/<OBJECT_NAME>

...而不是“真正的”gcs网址,例如

https://www.googleapis.com/storage/v1/b/<BUCKET_NAME>/<OBJECT_NAME>

...因此在为gcs对象发出GET请求时导致404错误。

TLDR

我能够通过简单地设置访问令牌来解决这个问题,例如

cloudstorage.common.set_access_token("<TOKEN>")

*请参阅下面的set_access_token文档字符串,了解如何获取访问令牌。

一旦我这样做,我的所有gcs请求都被正确路由。

详细

在挖掘appengine-gcs-client def set_access_token(access_token): """Set the shared access token to authenticate with Google Cloud Storage. When set, the library will always attempt to communicate with the real Google Cloud Storage with this token even when running on dev appserver. Note the token could expire so it's up to you to renew it. When absent, the library will automatically request and refresh a token on appserver, or when on dev appserver, talk to a Google Cloud Storage stub. Args: access_token: you can get one by run 'gsutil -d ls' and copy the str after 'Bearer'. """ 之后,如果您想使用dev_appserver访问gcs中的实时/远程内容,则必须先设置访问令牌。

source code中:

def _get_storage_api(retry_params, account_id=None):
  """Returns storage_api instance for API methods.
  Args:
    retry_params: An instance of api_utils.RetryParams. If none,
     thread's default will be used.
    account_id: Internal-use only.
  Returns:
    A storage_api instance to handle urlfetch work to GCS.
    On dev appserver, this instance will talk to a local stub by default.
    However, if you pass the arguments --appidentity_email_address and
    --appidentity_private_key_path to dev_appserver.py it will attempt to use
    the real GCS with these credentials.  Alternatively, you can set a specific
    access token with common.set_access_token.  You can also pass
    --default_gcs_bucket_name to set the default bucket.
  """

cloudstorage.common中的一些其他提示/选项:

google-api-python-client==1.6.4
GoogleAppEngineCloudStorageClient==1.9.22.1

其他信息

pip libs

Google Cloud SDK 200.0.0
alpha 2018.04.30
app-engine-python 1.9.69
app-engine-python-extras 1.9.69
beta 2018.04.30
bq 2.0.33
cloud-datastore-emulator 1.4.1
core 2018.04.30
gsutil 4.31

gcloud libs

if(status==kCLAuthorizationStatusAuthorizedWhenInUse) {
        float latitude;
        float longitude;
        CLLocationCoordinate2D coordinate = [self myLocation];
        latitude = coordinate.latitude;
        longitude = coordinate.longitude;
        status = [CLLocationManager authorizationStatus];

    CLLocation *location = [[CLLocation alloc] initWithLatitude:latitude longitude:longitude];

    CLGeocoder*myGeocoder = [[CLGeocoder alloc] init];

    [myGeocoder
     reverseGeocodeLocation:location
     completionHandler:^(NSArray *placemarks, NSError *error) {

         if (error == nil && placemarks.count > 0){

             CLPlacemark *placemark = placemarks[0];
             if ([placemark.locality isEqualToString:@"Mumbai"]) {
                 NSLog(@"Location is Mumbai");
             }
             else{
                 if (placemark.locality) {
                     alert=[UIAlertController alertControllerWithTitle:nil message:[NSString stringWithFormat:@"This app is not available @%@",placemark.locality] preferredStyle:UIAlertControllerStyleAlert];
                     [self presentViewController:alert animated:YES completion:nil];
                 }
                 else{
                     alert=[UIAlertController alertControllerWithTitle:nil message:@"This app is not available at your location" preferredStyle:UIAlertControllerStyleAlert];
                     [self presentViewController:alert animated:YES completion:nil];
                 }
             }


         }
         else if (error == nil && placemarks.count == 0){
             NSLog(@"No results were returned.");
         }
         else if (error != nil) {
             NSLog(@"An error occurred = %@", error);
         }
     }];
}
else{

    alert=[UIAlertController alertControllerWithTitle:@"Location Permission" message:@"To re-enable, please go to Settings and turn on Location Service for this app." preferredStyle:UIAlertControllerStyleAlert];
    UIAlertAction *Retry=[UIAlertAction actionWithTitle:@"Retry" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
       [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
        exit(0);
    }];
    [alert addAction:Retry];
    [self presentViewController:alert animated:YES completion:nil];
}