2016-08-14 13 views
7

हरोकू पर तैनात Django परियोजनाओं में, मैं boto के माध्यम से Google क्लाउड स्टोरेज में फ़ाइलों को अपलोड करता था। हालांकि, हाल ही में मुझे बड़ी फाइलें अपलोड करनी होंगी जो हरोकू टाइमआउट का कारण बनेंगी।डीजेगो, हेरोकू, बोटो: Google क्लाउड स्टोरेज पर सीधे फ़ाइल अपलोड

पायथन:

conn = boto.connect_gs(gs_access_key_id=GS_ACCESS_KEY, 
         gs_secret_access_key=GS_SECRET_KEY) 
presignedUrl = conn.generate_url(expires_in=3600, method='PUT', bucket=<bucketName>, key=<fileName>, force_http=True) 

जे एस:

मैं इस प्रकार Heroku के प्रलेखन के बारे में direct file upload to S3, और अनुरूपण अनुसरण कर रही हूं

url = 'https://<bucketName>.storage.googleapis.com/<fileName>?Signature=...&Expires=1471451569&GoogleAccessId=...'; // "presignUrl" 

postData = new FormData(); 
postData.append(...); 
... 

$.ajax({ 
    url: url, 
    type: 'PUT', 
    data: postData, 
    processData: false, 
    contentType: false, 
}); 

मैं निम्नलिखित त्रुटि संदेश मिला:

XMLHttpRequest cannot load http:/... Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8000' is therefore not allowed access. 

संपादित करें:

gsutil cors get gs://<bucketName> के उत्पादन:

[{"maxAgeSeconds": 3600, "method": ["GET", "POST", "HEAD", "DELETE", "PUT"], "origin": ["*"], "responseHeader": ["Content-Type"]}] 

ऐसा लगता है CORS ठीक है। तो, मैं समस्या को कैसे हल करूं? धन्यवाद।

संपादित करें 2:

फ़ायरफ़ॉक्स से विकल्प अनुरोध के शीर्षक:

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 
Accept-Encoding: gzip, deflate 
Accept-Language: zh-TW,zh;q=0.8,en-US;q=0.5,en;q=0.3 
Access-Control-Request-Method: PUT 
Connection: keep-alive 
Host: <bucketName>.storage.googleapis.com 
Origin: http://localhost:8000 
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:48.0) Gecko/20100101 Firefox/48.0 

क्रोम से विकल्प अनुरोध के शीर्षक:

Accept:*/* 
Accept-Encoding:gzip, deflate, sdch 
Accept-Language:zh-TW,zh;q=0.8,en;q=0.6,en-US;q=0.4,zh-CN;q=0.2 
Access-Control-Request-Headers: 
Access-Control-Request-Method:PUT 
Connection:keep-alive 
Host:directupload.storage.googleapis.com 
Origin:http://localhost:8000 
Referer:http://localhost:8000/ 
User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 
X-Client-Data:CIe2yQEIprbJAQjznMoB 
+0

यह मदद मिलेगी अगर आप preflight के लिए शीर्षलेखों शामिल (विकल्प) अनुरोध और प्रतिक्रिया वह aders। अनुरोध पर विशेष रूप से एक्सेस-कंट्रोल-अनुरोध- * और मूल शीर्षलेख और ACCESS-CONTROL- * प्रतिक्रिया पर शीर्षलेख। –

+0

क्या आप अधिक विस्तृत करेंगे क्योंकि मुझे नहीं पता कि उन डेटा को कैसे शामिल किया जाए। बहुत बहुत धन्यवाद। –

+0

सबसे आसान तरीका आपके ब्राउज़र के डेवलपर टूल का उपयोग करना होगा (आमतौर पर एफ 12 लेकिन हमेशा नहीं। उदाहरण के लिए ओएस एक्स पर क्रोम OPTION-COMMAND-i का उपयोग करता है)। डेवलपर टूल में नेटवर्क टैब होना चाहिए। सुनिश्चित करें कि यह यातायात को कैप्चर कर रहा है, प्रत्येक ब्राउज़र थोड़ा अलग है। फिर आगे बढ़ें और अपना AJAX अनुरोध करें, ब्राउज़र को आउटगोइंग अनुरोध और प्रतिक्रिया को कैप्चर करना चाहिए।यदि आप उचित अनुरोध का चयन करते हैं तो आपको ब्राउज़र से अनुरोध और सर्वर से प्रतिक्रिया दोनों के बारे में जानकारी का एक समूह देखने में सक्षम होना चाहिए। –

उत्तर

3

हैडर मुद्दा से नहीं आ रही है आपका ऐप, मुझे लगता है कि यह क्लाउड स्टोरेज बाल्टी से आ रहा है। एपीआई सेट करते समय मुझे एक ही समस्या थी, जिस संसाधन को आप पोस्ट कर रहे हैं वह हेडर गायब है।

https://cloud.google.com/storage/docs/cross-origin

जबकि दुर्भावनापूर्ण व्यवहार को रोकने के लिए उपयोगी है, इस सुरक्षा उपाय भी जाना जाता मूल के बीच उपयोगी और वैध बातचीत से बचाता है। उदाहरण के लिए, उदाहरण के लिए Google App Engine से होस्ट किए गए पृष्ठ पर एक स्क्रिप्ट उदाहरण के लिए .appspot.com क्लाउड स्टोरेज बाल्टी में संग्रहीत स्थिर संसाधनों का उपयोग करना चाह सकता है उदाहरण के लिए .storage.googleapis.com। हालांकि, क्योंकि ब्राउज़र के परिप्रेक्ष्य से ये दो अलग-अलग मूल हैं, ब्राउज़र example.appspot.com से example.stspot.com से संसाधनों को लाने के लिए XML.ttorage.googleapis.com से संसाधन लाने के लिए अनुमति नहीं देगा क्योंकि संसाधन प्राप्त किया जा रहा है अलग उत्पत्ति

तो ऐसा लगता है कि आपको कॉर्स अनुरोधों को अनुमति देने के लिए बाल्टी को कॉन्फ़िगर करने की आवश्यकता है। Google दस्तावेज़ Google क्लाई से चलाने के लिए निम्न कोड दिखाता है।

https://cloud.google.com/storage/docs/cross-origin#Configuring-CORS-on-a-Bucket

gsutil cors set cors-json-file.json gs://example 

[ 
    { 
     "origin": ["http://mysite.heroku.com"], 
     "responseHeader": ["Content-Type"], 
     "method": ["GET", "HEAD", "DELETE", "PUT"], 
     "maxAgeSeconds": 3600 
    } 
] 

कौन सा, की अनुमति होगी अपलोड आप मिलता है, और सामग्री को हटा दें। उम्मीद है की वो मदद करदे।

+0

अभी भी काम नहीं कर रहा है। मैंने अपने प्रश्न में EDIT भाग जोड़ा है। –

1

EDIT 2 में जानकारी के आधार पर, अनुरोध के साथ कुछ गलत है। प्रीफलाइट (विकल्प) अनुरोध में हेडर ACCESS-CONTROL-REQUEST-HEADER शामिल है। यह वैध कोर हेडर नहीं है। सही शीर्षलेख ACCESS-CONTROL-REQUEST-HEADERS है, अंत में 'एस' पर ध्यान दें।

यदि हेडर सही था, तो भी access-control-allow-origin शीर्षलेख के लिए प्राधिकरण का अनुरोध नहीं करना चाहिए। ACCESS-CONTROL-ALLOW-ORIGIN क्लाइंट से भेजा गया कोई हेडर नहीं है। यह एक हेडर है जो सर्वर से प्रीफ़लाइट अनुरोध प्राप्त होने पर सर्वर से प्रतिक्रिया में स्वचालित रूप से भेजा जाएगा। क्लाइंट/ब्राउजर क्रॉस-मूल PUT अनुरोध की अनुमति नहीं देगा जब तक कि यह ACCESS-CONTROL-ALLOW-ORIGIN हेडर को पूर्व-प्रकाश अनुरोध में क्रॉस-मूल सर्वर से ब्राउज़र दस्तावेज़ की वर्तमान उत्पत्ति को अधिकृत करने वाला हेडर प्राप्त नहीं करता है।

खराब हेडर की उपस्थिति आपको प्राप्त होने वाली त्रुटि प्रतिक्रिया के साथ अच्छी तरह से सहसंबंधित प्रतीत होती है। हालांकि, ऐसा लगता है कि हेडर शायद आपके मूल कोड में नहीं था, ऐसा लगता है कि आपने इसे बाद में जोड़ा (आपकी टिप्पणियों के आधार पर)। उस हेडर कॉन्फ़िगर को लेना सुनिश्चित करें, यह निश्चित रूप से सही नहीं है।

तो मैं उस बारे में थोड़ा उलझन में हूं कि वह हेडर कहां से आ रहा है, लेकिन मुझे लगता है कि यह आपकी समस्या का स्रोत है।

ऐसा लगता है कि आप AJAX PUT अनुरोध करने के लिए jQuery का उपयोग कर रहे हैं। मैं वास्तव में सुझाव दे सकता हूं कि आपने यह सुनिश्चित किया है कि आपने अपने जेएस कोड में $ .ajaxSetup() कहीं नहीं कहा है जो खराब हेडर को कॉन्फ़िगर कर रहा है।

+0

बहुत बहुत धन्यवाद, जॉडी। 'एक्सेस-कंट्रोल-रिक्वेस्ट-हेडर' ('एस' के बिना) मेरी खराब कॉपी-एंड-पेस्ट से सिर्फ एक टाइपो है। उसके लिए माफ़ करना। हां, मैंने AJAX PUT अनुरोध में ऐसा हेडर जोड़ा था; तो, मुझे गलत विचार मिला। EDIT 2 को अनदेखा करते हुए, क्या आप एक और विशिष्ट सुझाव प्रदान करेंगे। मेरा पूरा कोड प्रश्न (पायथन और जेएस) में है, और मैंने कोई '$ .ajaxSetup()' नहीं किया है। –

+0

प्रतिक्रिया को खोलने के लिए बाल्टी पर सीओआरएस कॉन्फ़िगरेशन में बदलने का प्रयास करें। –

+0

उदाहरण: '[{" maxAgeSeconds ": 3600," विधि ": [" प्राप्त करें "," पोस्ट "," HEAD "," हटाएं "," PUT "]," मूल ": [" * "]," प्रतिक्रिया हैडर ": [" * "]}] –

0

इतने सारे परीक्षणों और त्रुटियों के बाद, मैं निम्नलिखित के साथ आया। कार्यक्रमों ने काम किया, हालांकि, कभी-कभी अपलोड की गई छवियों में से कुछ दिखाई नहीं दे रहे हैं; अन्य बार वे ठीक हैं। मुझे नहीं पता कि यह क्यों हुआ।

मैं अधिक विचार पूछना चाहता हूं कि फ़ाइल अपलोड ठीक क्यों हैं लेकिन कुछ छवियां दूषित हैं।

gsutil कमांड:

gsutil cors set cors.json gs://<bucketName> 
gsutil defacl ch -u allUsers:R gs://<bucketName> 

सामग्री की cors.json फ़ाइल:

[ 
    { 
     "origin": ["*"], 
     "responseHeader": ["Content-Type"], 
     "method": ["GET", "POST", "HEAD", "DELETE", "PUT"], 
     "maxAgeSeconds": 3600 
    } 
] 

HTML:

<p id=status>Choose your avatar:</p> 
<input id=fileInput type=file> 

जावास्क्रिप्ट:

$(document).on('change', '#fileInput', function() { 
    var $this = $(this); 
    var file = $this[0].files[0]; 

    $.ajax({ 
    url: 'upload/sign/?fileName=' + file.name + '&contentType=' + file.type, 
    type: 'GET' 
    }) 
    .done(function(data) { 
    var response = JSON.parse(data); 
    uploadFile(file, response.presignedUrl, response.url, response.contentType) 
    }) 
    .fail(function() { 
    alert('Unable to obtain a signed URL.'); 
    }); 
}); 

function uploadFile(file, presignedUrl, url, contentType) { 
    var postData = new FormData(); 
    postData.append('file', file); 

    $.ajax({ 
    url: presignedUrl, 
    type: 'PUT', 
    data: postData, 
    headers: { 
     'Content-Type': contentType, 
    }, 
    processData: false, 
    contentType: false 
    }) 
    .done(function() { 
    alert('File upload successful'); 
    }) 
    .fail(function() { 
    alert('Unable to upload the file.'); 
    }); 
} 

Django:

परियोजना की urls.py:

urlpatterns = [ 
    ... 
    url(r'upload/', include('upload.urls', namespace='upload')), 
] 

एप्लिकेशन की urls.py:

urlpatterns = [ 
    url(r'^$', views.upload, name='upload'), 
    url(r'^sign/', views.sign, name='sign'), 
] 

views.py:

def upload(request): 
    # ... render the template 


def sign(request): 
    fileName = request.GET.get('fileName') 
    contentType = request.GET.get('contentType') 
    conn = boto.connect_gs(gs_access_key_id=GS_ACCESS_KEY, 
          gs_secret_access_key=GS_SECRET_KEY) 
    presignedUrl = conn.generate_url(3600, 'PUT', GS_BUCKET_NAME, fileName, headers={'Content-Type':contentType}) 
    return HttpResponse(
     json.dumps({ 
      'presignedUrl': presignedUrl, 
      'url': GS_URL + fileName, 
      'contentType': contentType 
     }) 
    ) 
+0

कई परीक्षणों और त्रुटियों के बाद, मैंने पाया कि उपरोक्त कोड पीडीएफ और सादे पाठ फ़ाइलों के लिए काम करता है। केवल छवि फ़ाइलों में समस्याएं हैं। क्यूं कर? –

संबंधित मुद्दे