Invalid location of tag (form) 错误[原创+转载]

本文解决了一个关于HTML表单放置的问题,即<form>标签不应位于<table>标签内部,这会导致MyEclipse等IDE给出Invalid location of tag(form)的警告。通过调整表单标签的位置可以消除此类警告。

最近遇到了个问题,有一个列表提交,第一条记录点击的时候浏览器总是报错,说第一个form没有定义。从代码上看得出是有定义的,然后看看myeclipse里面的提示,是Invalid location of tag (form) ,于是上网查了下,得出的结论都是:

MyEclipse提示正常了,原因在此:
<form></form>不能写到<table></table>里面!

所以,我把没必要的form标签去掉就可以了

 

import http.server import time import socketserver import os import threading import socket import json #下面的导入从SimpleHTTPServer.py复制: import posixpath import urllib.parse import cgi import sys import shutil import mimetypes import io import re #从jfrog下载并解压文件-开始 from file_downloader import FileDownloader # 创建 FileDownloader 实例 print(f"start download file \n") downloader = FileDownloader() # 执行下载和解压 downloader.execute() #从jfrog下载并解压文件-结束 PORT = 8000 i = 1 class MyThreadingHTTPServer(socketserver.ThreadingTCPServer): allow_reuse_address = 1 def server_bind(self): """Override server_bind to store the server name.""" socketserver.TCPServer.server_bind(self) host, port = self.socket.getsockname()[:2] self.server_name = socket.getfqdn(host) self.server_port = port #Handler = SimpleHTTPServer.SimpleHTTPRequestHandler class MyHTTPRequestHandler(http.server.SimpleHTTPRequestHandler): def dumpRequestHeaders(self): pass #print 'dumpRequestHeaders: raw_requestline=%s \nheaders=\n%s' % (self.raw_requestline,self.headers) def copyfile_by_range(self, fin, fout, start, end): print( "copyfile_by_range: start=%d end=%d" % (start, end)) READ_BUFFER_SIZE = 4*1024; fin.seek(start, os.SEEK_SET) if end<0: #代表原始Range请求未指定完整范围,只指定了开始位置 buf = fin.read(READ_BUFFER_SIZE) #FIXME:健壮性fix,如果读到内容小于size参数?需要判断len(buf) if len(buf)!=READ_BUFFER_SIZE: pass #print "copyfile_by_range: len(buf)!=READ_BUFFER_SIZE 1 len(buf)=%d" % (len(buf)) while buf: fout.write(buf) fout.flush() buf = fin.read(READ_BUFFER_SIZE) if len(buf)==0: break #?? if len(buf)!=READ_BUFFER_SIZE: pass #print "copyfile_by_range: len(buf)!=READ_BUFFER_SIZE 2 len(buf)=%d" % (len(buf)) fout.write(buf) break else: bytes_left = end-start+1 while bytes_left >= READ_BUFFER_SIZE: buf = fin.read(READ_BUFFER_SIZE) if len(buf)!=READ_BUFFER_SIZE: pass #print "copyfile_by_range: len(buf)!=READ_BUFFER_SIZE 3 len(buf)=%d" % (len(buf)) fout.write(buf) bytes_left = bytes_left - READ_BUFFER_SIZE if bytes_left>0: buf = fin.read(bytes_left) if len(buf)!=bytes_left: pass #print "copyfile_by_range: len(buf)!=bytes_left len(buf)=%d bytes_left=" % (len(buf), bytes_left) fout.write(buf) def do_GET(self): self.dumpRequestHeaders() #用于查看客户端浏览器的User-Agent设置; # #SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self) f, range = self.send_head() #原来的send_head这个函数实现有点莫名其妙? if f: if range: #注意,响应头部已经在send_head()里设置完成了,这里只需要调整io读写指针 self.copyfile_by_range(f, self.wfile, range[0], range[1]) else: self.copyfile(f, self.wfile) f.close() #重载SimpleHTTPServer.py里的实现,以实现:(1)按修改日期排序(2)正确显示中文 #TODO:支持更多查询参数?html输出代码美化? def list_directory(self, path): """Helper to produce a directory listing (absent index.html). Return value is either a file object, or None (indicating an error). In either case, the headers are sent, making the interface the same as for send_head(). """ try: list = os.listdir(path) except os.error: self.send_error(404, "No permission to list directory") return None #list.sort(key=lambda a: a.lower()) ''' def compare_by_modtime(x, y): stat_x = os.stat(path + "/" + x) stat_y = os.stat(path + "/" + y) if stat_x.st_mtime < stat_y.st_mtime: return -1 elif stat_x.st_mtime > stat_y.st_mtime: return 1 else: return 0 list.sort(lambda x,y: compare_by_modtime(y,x)) #最近修改的排在前面 ''' def key_by_mtime(a): try: return - os.stat(path + "/" + a).st_mtime except Exception as e: return 0 #?? list.sort(key=key_by_mtime) f = [] enc = "gb18030"; displaypath = cgi.escape(urllib.parse.unquote(self.path)) f.append('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" ' '"http://www.w3.org/TR/html4/strict.dtd">') f.append('<html>\n<head>') f.append('<meta http-equiv="Content-Type" ' 'content="text/html; charset=%s">' % enc) f.append("<title>Directory listing for %s</title>\n" % displaypath) f.append("<body>\n<h2>Directory listing for %s</h2>\n" % displaypath) f.append("<hr>\n<ul>\n") for name in list: fullname = os.path.join(path, name) displayname = linkname = name is_dir = False # Append / for directories or @ for symbolic links if os.path.isdir(fullname): displayname = name + "/" linkname = name + "/" is_dir = True if os.path.islink(fullname): displayname = name + "@" # Note: a link to a directory displays with @ and links with / f.append('<li><a href="%s">%s</a>\n' % (urllib.parse.quote(linkname), cgi.escape(displayname))) #self.path是浏览器请求路径,而path是本地文件系统路径 if not is_dir and name.endswith('.mp4'): f.append('|<a href="/playvideo?path=%s">播放</a>\n' % (urllib.parse.quote( os.path.join(self.path, name)))) f.append('</li>') f.append("</ul>\n<hr>\n</body>\n</html>\n") encoded = '\n'.join(f).encode(enc, 'surrogateescape') b = io.BytesIO() b.write(encoded) b.seek(0) self.send_response(200,"success") encoding = "gbk" #sys.getfilesystemencoding() self.send_header("Content-Type", "text/html; charset=%s" % encoding) self.send_header("Content-Length", str(len(encoded))) self.end_headers() return b #TODO:支持Range请求,这样可以提供基于HTTP的视频流媒体服务 def send_head(self): """ overwrite send_head to set Last-Modified & Expires to disable browser cache; """ enc = "gb18030"; unquoted_path = urllib.parse.unquote(self.path) print( "send_head: self.path=%s unquoted_path=%s" % (self.path, unquoted_path)) PLAYVIDEO_REQUEST = re.compile(r'/playvideo\?path=(.+)$') m = PLAYVIDEO_REQUEST.match(unquoted_path) if m: #TODO: 重构这里的代码 video_path = m.group(1) print( "send_head: video_path=%s" % video_path) self.send_response(200) self.send_header("Content-Type", "text/html") self.end_headers() self.wfile.write(('<video src="%s" controls></video>' % video_path).encode(enc, 'surrogateescape')) #注意,这个地方不需要urllib.quote return (None,None) path = self.translate_path(self.path) f = None if os.path.isdir(path): if not self.path.endswith('/'): # redirect browser - doing basically what apache does self.send_response(301) sa = s.socket.getsockname() self.send_header("Location", "http://" + str(sa[0]) + ":" + str(sa[1]) + self.path + "/icc_delta.zip_E.51") self.wfile.flush() time.sleep(1) self.end_headers() return (None,None) for index in "index.html", "index.htm": index = os.path.join(path, index) if os.path.exists(index): path = index break else: return (self.list_directory(path), None) ctype = self.guess_type(path) try: # Always read in binary mode. Opening files in text mode may cause # newline translations, making the actual size of the content # transmitted *less* than the content-length! f = open(path, 'rb') #Get file size: f.seek(0, os.SEEK_END) filesize = f.tell() f.seek(0, os.SEEK_SET) #TODO: 检查原始请求是否指定了Range头部 if self.headers.get("Range"): range_value = self.headers["Range"] #range_value = "bytes=31219987-71219986" print( "send_head: range_value=[%s]" % range_value) #直接使用正则表达式匹配: Range: bytes=100- HTTP_RANGE_HEADER = re.compile(r'bytes=([0-9]+)\s*\-\s*(([0-9]+)?)') m = re.match(HTTP_RANGE_HEADER, range_value) if m: start_str = m.group(1) start = int(start_str) end_str = m.group(2) end = -1 if len(end_str)>0: end = int(end_str) #现在可以写Range响应头部了: self.send_response(206, "Partial Content") self.send_header("Content-Type", ctype) if end==-1: self.send_header("Content-Length", str(filesize-start)) else: self.send_header("Content-Length", str(end-start+1)) self.send_header("Accept-Ranges", "bytes") if end<0: content_range_header_value = "bytes %d-%d/%d" % (start, filesize-1, filesize) else: content_range_header_value = "bytes %d-%d/%d" % (start, end, filesize) self.send_header("Content-Range", content_range_header_value) print( "send_head: ok, serve 206 for Range request %s-%s,Content-Range=%s" % (start_str, end_str, content_range_header_value)) self.send_header("Connection", "close") self.end_headers() return (f, [start, end]) else: print( "send_head: error! INVALID Range request header!!") self.send_error(400, "Bad Request") self.wfile.flush() self.end_headers() return (None,None) except IOError: self.send_error(404, "File not found") return (None,None) self.send_response(200,"success") self.send_header("Content-Type", ctype) file_stat = os.fstat(f.fileno()) self.send_header("Content-Length", str(file_stat[6])) #self.send_header("Last-Modified", self.date_time_string(file_stat.st_mtime)) self.send_header("Last-Modified", self.date_time_string(time.time())) #self.send_header("Expires", self.date_time_string(time.time()+5)) #self.send_header("Cache-control", "no-cache, no-store, must-revalidate, max-age=0, proxy-revalidate, no-transform") #self.send_header("Pragma", "no-cache") self.send_header("Connection", "close") self.end_headers() return (f, None) def do_POST(self): print(self.path) if self.path == '/upload/log_package': self.handle_chunked_upload() if self.path == '/request_package_url.cgi': self.handle_post_url() else: # 处理其他POST请求(如果有的话) pass def handle_post_url(self): # 构造符合指定格式的响应 response = [ {"ModuleID":"51","URL":"http://0.0.0.0:8000/ICC_mpu/cloud_iccmpu322483.51"} ] print(response) # 返回处理结果 self.send_response(200, "success") self.send_header('Content-Type', 'application/json') self.end_headers() self.wfile.write(json.dumps(response).encode('utf-8')) return def handle_chunked_upload(self): global i print(i) content_type, _ = cgi.parse_header(self.headers.get('Content-Type')) content_range, _ = cgi.parse_header(self.headers.get('Content-Range')) lst = re.split(r"[-/]", content_range) print(lst) if content_type == 'multipart/form-data': form_data = cgi.FieldStorage( fp=self.rfile, headers=self.headers, environ={'REQUEST_METHOD': 'POST', 'CONTENT_TYPE': self.headers['Content-Type']} ) # 获取分片相关信息 total_chunks = int(lst[2]) current_chunk = int(lst[1]) file_name = "1632778555351_0123456789V000001_20210927_213557_14869_ota_V1.zip" # 将分片保存到指定位置 upload_path = '/fota/' # 替换为你希望保存上传文件的目录 part = file_name + '_part_' + str(i) file_path = os.path.join(upload_path, part) print(file_path) with open(file_path, 'wb') as new_file: new_file.write(form_data['file'].file.read()) new_file.flush() os.fsync(new_file.fileno()) # 如果是最后一个分片,组合分片 if current_chunk == total_chunks: combined_file_path = os.path.join(upload_path, file_name) with open(combined_file_path, 'ab') as combined_file: for chunk_num in range(1, i+1): print(chunk_num) part_num = file_name + '_part_' + str(chunk_num) part_file_path = os.path.join(upload_path, part_num) print(part_file_path) with open(part_file_path, 'rb') as part_file: combined_file.write(part_file.read()) print("write success") os.remove(part_file_path) # 删除已经组合的分片文件 print("delete success") # 构造符合指定格式的响应 response = { 'code': 200, 'message': 'success', 'data': { 'fileUrl': 'http://0.0.0.0:8000/upload/log_package' # 替换为服务器地址 } } # 用JSON格式回应客户端 self.send_response(200, "success") self.send_header('Content-Type', 'application/json') self.end_headers() self.wfile.write(json.dumps(response).encode('utf-8')) return # 如果不是最后一个分片,简单返回成功 response = { 'code': 200, 'message': 'success' } # 用JSON格式回应客户端 i = i + 1 self.send_response(200, "success") self.send_header('Content-Type', 'application/json') self.end_headers() self.wfile.write(json.dumps(response).encode('utf-8')) return else: i = 1 self.send_error(400, '请求错误:文件上传的内容类型无效') return s = MyThreadingHTTPServer(("", PORT), MyHTTPRequestHandler) sa = s.socket.getsockname() print("Serving MyThreadingHTTPServer on", sa[0], "port", sa[1], "...") s.serve_forever() 参考这个python 代码的实现来写c++
10-24
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值