我编写了一个简单的程序,将 JPG 图像从我的 arduino 上传到 Google Drive。我使用指南中描述的 POST 请求。如果我尝试上传 1600*1200 的图像,有时它可以工作(200),有时不能(308),我不知道为什么。然后,当我收到 308 时,它不会按照指南中的说明将字节范围标头发回给我。
我注意到,如果我正在看电影,响应 308 并且当我停止电影时,过一会儿上传成功
给我带来问题的功能是这个:
bool httpsUploadFromSD(class Token token, String filepath) {
WiFiSSLClient client = token.getClient(); // I get the client class
File image = SD.open(filepath, FILE_READ); // I open the file I want to send
String name_metadata ="{\"name\": \"" + String(image.name()) + "\"}";
if (!image) {
Serial.println("FILE OPEN FAILED");
return false;
} else {
Serial.println("IMAGE OPENED of size" + String(image.size()));
}
bool received = false;
bool trytorefresh = false;
unsigned long startTime = millis();
String code = "";
String uploadID = "";
// Connecting -- Asking for upload permission
Serial.println("Asking for upload...");
do {
// Sending the upload request
if (client.connect("www.googleapis.com", 443)) {
client.println("POST /upload/drive/v3/files?uploadType=resumable HTTP/1.1");
client.println("Host: www.googleapis.com");
client.println("Authorization: " + token.token_type + " " + token.access_token);
client.println("Content-Length: " + String(name_metadata.length()));
client.println("Content-Type: application/json; charset=UTF-8");
client.println("X-Upload-Content-Type: image/jpeg");
client.println("X-Upload-Content-Length: " + String(image.size()));
client.println("Connection: close");
client.println();
client.println(name_metadata);
client.println();
Serial.println("Upload request sent");
received = false;
} else {
Serial.println("connection failed");
received = true;
}
//Listen to the client responsse
while ((millis() - startTime < 5000) && !received) { //try to listen for 5 seconds
int i = 0;
while (client.available() && i < 12) {
received = true;
char c = client.read();
Serial.write(c);
code = code + c;
i++;
}
//When I reckognize 200 I enter here and identify the uploadID;
if(i>0){
if (code == "HTTP/1.1 200") {
while (client.available()) {
char c = client.read(); // here I print in the Serial the response
Serial.write(c);
if (c == ':') {
c = client.read();
Serial.write(c);
c = client.read();
Serial.write(c);
do {
uploadID = uploadID + c; // Here I identify UploadID from the resp
c = client.read();
Serial.write(c);
} while (c != '\n');
break;
}
}
break;
}
else if (code == "HTTP/1.1 401") {
while(client.available()) {
char c = client.read();
Serial.write(c);
}
// If credentials are not valide, I'll try once to refresh the token;
if(!trytorefresh){
Serial.println("\nProbably you need to refresh the token\nI'm trying to refresh\n");
token.httpsTokenRefresh();
trytorefresh = !trytorefresh;
}
}
else if (code == "HTTP/1.1 400") {
while(client.available()) {
char c = client.read();
Serial.write(c);
}
break;
} else {
break;
}
}
}
} while (trytorefresh); // I try to refresh once if the resposnse is 401
if (code == "HTTP/1.1 200") {
// I stop the previous client session, because now I start a new one, to do the PUT request and upload the file
client.stop();
Serial.println("Token request has been succesful. Starting upload");
bool succesful = false;
// I have obtained the uploadID, now I start uploading
String location = "https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable&upload_id=" + uploadID;
while(!succesful){ // I upload until it is successful
// Upload request
if (client.connect("www.googleapis.com", 443)) {
client.println("PUT " + location + " HTTP/1.1");
client.println("User-Agent: Arduino Camera");
client.println("Content-Length: " + String(image.size()));
client.println("Connecion: close");
client.println();
while (image.available()) {
client.write(image.read()); // Here I send the bytes of the image
}
image.close();
received = false;
} else {
Serial.println("Connection failed");
received = true;
}
// Listening to the response
startTime = millis();
String code = "";
while ((millis() - startTime < 5000) && !received) { //try to listen for 5 seconds
int i = 0;
while (client.available() && i < 12) {
received = true;
char c = client.read();
Serial.write(c);
code = code + c;
i++;
}
// HTTP 200 OK
if (code == "HTTP/1.1 200" || code == "HTTP/1.1 201")
{
while(client.available()) {
char c = client.read();
Serial.write(c);
}
Serial.println("\n\nUpload succesful");
succesful = true;
client.stop();
return succesful;
}
// HTTP 308 I have to restart my upload
else if (code == "HTTP/1.1 308") {
// Here I print the response in serial and I identify the range to re-send. Actually it always happens that the range header is not present, so I re-send the whole image
bool range_present = false;
char Range[] = "xxxxxx";
String byte_range = "";
uint32_t re_send_length = 0;
while (client.available()) {
for (int k = 0; k<5; k++){
Range[k] = Range[k++];
}
char c = client.read();
Range[5] = c;
Serial.write(c);
if (Range == "Range:") {
break;
range_present = true;
}
}
if (range_present) {
int k = 0;
while (client.available() && k<7) {
char c = client.read();
Serial.write(c);
}
k = 0;
String Range2 = "";
while (client.available()) {
char c = client.read();
Serial.write(c);
if (c == '\n') {
break;
}
Range2 = Range2 + c;
}
while (client.available()) {
char c = client.read();
Serial.write(c);
}
bool a = false;
for (k = 0; k<Range2.length(); k++) {
if (a) {
byte_range = byte_range + Range2[k];
}
if (Range2[k] = '-') {
a = true;
}
}
Serial.println("byte_range = " + byte_range);
}
Serial.println("\n\nUpload interrupted. Starting a new session");
// I have to open image again
image = SD.open(filepath, FILE_READ);
delay(1000);
}
}
}
} else if (code == "HTTP/1.1 401" && trytorefresh) {
Serial.println("Upload failed. Probably you need a new token");
}
client.stop();
return false;
}
这里有令牌类
class TokenRequestData {
public:
TokenRequestData();
TokenRequestData(String deviceCode, String userCode, int expiresIn, int Interval, String verificationUrl, WiFiSSLClient Client);
String device_code;
String user_code;
int expires_in;
int interval;
String verification_url;
WiFiSSLClient client;
void httpsAskForTokenData();
};
class Token {
TokenRequestData data;
void httpsTokenPolling(class TokenRequestData requestData);
public:
Token();
Token(class TokenRequestData Data, String AccessToken, String RefreshToken, int ExpiresIn);
String access_token;
String refresh_token;
int expires_in;
String token_type;
void httpsTokenRequest(class TokenRequestData requestData);
void httpsTokenRefresh();
WiFiSSLClient getClient();
};