There is currently a huge disconnect between the needs of Web applications and the frameworks that support them. Admittedly, we have come a long, long way from the days of CGI, but we still have a long way to go. I am not quite ready to say that we need a new language aimed at Web development.
I think that the problems are not any more language specific than any other programming difficulty. But I do think that the current frameworks inadequately address the needs of a developer writing an actual application that has all of the same power and functionality as a client/server application, a mainframe application, or even a basic, disconnected desktop application. For the sake of discussion, I am going to stick with mainstream frameworks — J2EE, ASP.NET, and PHP. (I would love to include Ruby on Rails in this discussion, and maybe some of the readers can help with that, but my knowledge of it is just not high enough to write about it competently, and it definitely is not "mainstream" yet.)
Thread safety within the framework's shared objects
Point number one is the automatic parallelization of Web code. Whether most Web developers realize it or not, their code always runs the risk of simultaneous execution, even at the individual user level. In other words, imagine if you were writing a desktop application, and every button click, drag/drop action, and so on immediately executed the event handler in a separate thread. It would certainly change how you handle issues like data concurrency, the private variable access within classes, and so on, wouldn't it? This is exactly what you are facing while writing a Web based application. I am not necessarily saying that Web servers or Web frameworks should serialize all requests (although it would be nice if that was a configurable option, particularly at the user session level). Current Web frameworks pretend to handle this differently, but they rarely do in optimal or configurable ways. For example, the Microsoft ASP.NET documentation has this small blurb on the issue of session states and concurrency:
Access to ASP.NET session state is exclusive per session, which means that if two different users make concurrent requests, access to each separate session is granted concurrently. However, if two concurrent requests are made for the same session (that is, using the same SessionID value), then the first request received gains exclusive access to the session information and the second request will execute once the first request completes, or until the exclusive lock on the information is freed due to the first request exceeding the lock timeout. If the EnableSessionState page directive is set to ReadOnly, then a request for the read-only session information does not result in an exclusive lock on the session data. Read-only requests for session data may still have to wait for a lock gained by a read-write request for session data to clear.
In other words, the session data locks, but it is essentially an exclusive lock at the call level. The session object in ASP.NET does not support a mode or methods to grant locks for an entire page or section of code. It is up to the developer to do something like wrapping any code that calls the Session object in a critical section to keep that data safe.
PHP takes an entirely different tack. While the documentation does not formally mention the data concurrency challenge (another stellar example of what I mean when I say, "PHP's documentation is lousy"), a friendly visitor was nice enough to post some revealing information about the issue (see the comments in that documentation). If this user is correct, the use of sessions will lock on a call to the session object, which automatically forces the serial processing of pages; this is not exactly optimal, but at least it is guaranteed safe. The developer is forced to jump through some hoops to do anything else, according to that post.
And finally, the J2EE documentation for the HttpSession object does not mention the topic at all. Way to go, Sun! On a side note, it is interesting that Microsoft, who is traditionally slammed on documentation, discusses the issue better than anyone else does.
The page model
This is where the difficulty with the page model lies. Technologies like ASP.NET's Web Parts and J2EE's Faces is a great start. Let the "page" act as a container for these small chunks of functionality. It certainly comes much closer to the component writing and reuse that revolutionized desktop development ages ago. While the current frameworks are addressing this issue, there is still too much of the page model that needs to go, right down to the way the IDEs like Eclipse and Visual Studio conceptualize an "application." They are still geared for the page model that has proven itself to be poor for "applications." PHP, with its root so closely intertwined with CGI, lacks these kinds of tools. Instead, a PHP developer who wishes to do something similar fills their code with a lot of includes and such, which creates a complete mess as far as code is concerned.
This is really not about desktop apps vs. Web apps, but it also is in a way. Users and product managers are expecting more and more from Web applications. After all, most of us have the idea that Web applications are going to replace all of our client/server and mainframe applications (personally, I don't buy it). The problem is, the applications that Web apps try to replace have had seamless development models for quite some time now. The functionality capabilities of Web apps are still well below 1990 (if not 1985) levels in the desktop world. If Web apps are going to replace desktop apps, developers need the tools to build them just as good. And I really do not think that any of the current, mainstream frameworks come close.